summaryrefslogtreecommitdiff
path: root/Final/java/client
diff options
context:
space:
mode:
Diffstat (limited to 'Final/java/client')
-rw-r--r--Final/java/client/distribution/pom.xml156
-rw-r--r--Final/java/client/distribution/src/main/assembly/client-bin-tests.xml107
-rw-r--r--Final/java/client/distribution/src/main/assembly/client-bin.xml78
-rw-r--r--Final/java/client/distribution/src/main/assembly/client-java1.4-bin.xml74
-rw-r--r--Final/java/client/distribution/src/main/assembly/client-src.xml62
-rw-r--r--Final/java/client/example/bin/set_classpath.bat50
-rwxr-xr-xFinal/java/client/example/bin/set_classpath.sh83
-rw-r--r--Final/java/client/example/pom.xml152
-rw-r--r--Final/java/client/example/source-jar.xml35
-rw-r--r--Final/java/client/example/src/main/java/org/apache/qpid/example/log4j.xml45
-rw-r--r--Final/java/client/example/src/main/java/org/apache/qpid/example/publisher/FileMessageDispatcher.java162
-rw-r--r--Final/java/client/example/src/main/java/org/apache/qpid/example/publisher/FileMessageFactory.java136
-rw-r--r--Final/java/client/example/src/main/java/org/apache/qpid/example/publisher/MessageFactoryException.java54
-rw-r--r--Final/java/client/example/src/main/java/org/apache/qpid/example/publisher/MonitorMessageDispatcher.java141
-rw-r--r--Final/java/client/example/src/main/java/org/apache/qpid/example/publisher/MonitorPublisher.java104
-rw-r--r--Final/java/client/example/src/main/java/org/apache/qpid/example/publisher/Publisher.java181
-rw-r--r--Final/java/client/example/src/main/java/org/apache/qpid/example/publisher/UndeliveredMessageException.java57
-rw-r--r--Final/java/client/example/src/main/java/org/apache/qpid/example/pubsub/Client.java72
-rw-r--r--Final/java/client/example/src/main/java/org/apache/qpid/example/pubsub/ConnectionSetup.java123
-rw-r--r--Final/java/client/example/src/main/java/org/apache/qpid/example/pubsub/Publisher.java81
-rw-r--r--Final/java/client/example/src/main/java/org/apache/qpid/example/pubsub/Subscriber.java98
-rw-r--r--Final/java/client/example/src/main/java/org/apache/qpid/example/shared/ConnectionException.java54
-rw-r--r--Final/java/client/example/src/main/java/org/apache/qpid/example/shared/ContextException.java54
-rw-r--r--Final/java/client/example/src/main/java/org/apache/qpid/example/shared/FileUtils.java168
-rw-r--r--Final/java/client/example/src/main/java/org/apache/qpid/example/shared/InitialContextHelper.java80
-rw-r--r--Final/java/client/example/src/main/java/org/apache/qpid/example/shared/Statics.java57
-rw-r--r--Final/java/client/example/src/main/java/org/apache/qpid/example/shared/example.properties39
-rw-r--r--Final/java/client/example/src/main/java/org/apache/qpid/example/subscriber/MonitoredSubscriber.java139
-rw-r--r--Final/java/client/example/src/main/java/org/apache/qpid/example/subscriber/MonitoredSubscriptionWrapper.java51
-rw-r--r--Final/java/client/example/src/main/java/org/apache/qpid/example/subscriber/Subscriber.java181
-rw-r--r--Final/java/client/example/src/main/java/org/apache/qpid/example/subscriber/SubscriptionWrapper.java51
-rw-r--r--Final/java/client/pom.xml249
-rw-r--r--Final/java/client/src/main/java/client.log4j28
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/AMQAuthenticationException.java42
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/AMQBrokerDetails.java353
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/AMQConnection.java1289
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/AMQConnectionFactory.java409
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/AMQConnectionURL.java455
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/AMQDestination.java451
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/AMQHeadersExchange.java59
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/AMQNoConsumersException.java40
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/AMQNoRouteException.java40
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/AMQQueue.java149
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/AMQQueueBrowser.java136
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/AMQQueueSessionAdaptor.java204
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/AMQSession.java2800
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/AMQSessionAdapter.java26
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/AMQTemporaryQueue.java69
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/AMQTemporaryTopic.java72
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/AMQTopic.java115
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/AMQTopicSessionAdaptor.java226
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/AMQUndefinedDestination.java45
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/BasicMessageConsumer.java996
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/BasicMessageProducer.java691
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/Closeable.java83
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/ConnectionTuneParameters.java72
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/CustomJMSXProperty.java65
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/DispatcherCallback.java36
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/JMSAMQException.java65
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/JmsNotImplementedException.java31
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/MessageConsumerPair.java43
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/QpidConnectionMetaData.java97
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/QueueReceiverAdaptor.java115
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/QueueSenderAdapter.java230
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/SSLConfiguration.java61
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/TemporaryDestination.java38
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/TopicPublisherAdapter.java205
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/TopicSubscriberAdaptor.java126
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/failover/FailoverException.java49
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/failover/FailoverHandler.java240
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/failover/FailoverNoopSupport.java75
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/failover/FailoverProtectedOperation.java49
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/failover/FailoverRetrySupport.java128
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/failover/FailoverState.java64
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/failover/FailoverSupport.java47
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/handler/BasicCancelOkMethodHandler.java59
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/handler/BasicDeliverMethodHandler.java52
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/handler/BasicReturnMethodHandler.java53
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/handler/ChannelCloseMethodHandler.java105
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/handler/ChannelCloseOkMethodHandler.java50
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/handler/ChannelFlowOkMethodHandler.java52
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/handler/ConnectionCloseMethodHandler.java102
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/handler/ConnectionOpenOkMethodHandler.java48
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/handler/ConnectionRedirectMethodHandler.java73
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/handler/ConnectionSecureMethodHandler.java73
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/handler/ConnectionStartMethodHandler.java239
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/handler/ConnectionTuneMethodHandler.java97
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/handler/ExchangeBoundOkMethodHandler.java59
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/handler/QueueDeleteOkMethodHandler.java58
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/message/AMQMessage.java135
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/message/AbstractBytesMessage.java151
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/message/AbstractBytesTypedMessage.java801
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/message/AbstractJMSMessage.java685
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/message/AbstractJMSMessageFactory.java103
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/message/JMSBytesMessage.java388
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/message/JMSBytesMessageFactory.java43
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/message/JMSHeaderAdapter.java552
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/message/JMSMapMessage.java507
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/message/JMSMapMessageFactory.java43
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/message/JMSObjectMessage.java197
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/message/JMSObjectMessageFactory.java43
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/message/JMSStreamMessage.java204
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/message/JMSStreamMessageFactory.java43
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/message/JMSTextMessage.java201
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/message/JMSTextMessageFactory.java46
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/message/MessageConverter.java202
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/message/MessageFactory.java41
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/message/MessageFactoryRegistry.java127
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/message/UnexpectedBodyReceivedException.java45
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/message/UnprocessedMessage.java131
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/protocol/AMQProtocolHandler.java732
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/protocol/AMQProtocolSession.java459
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/protocol/BlockingMethodFrameListener.java311
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/protocol/HeartbeatConfig.java61
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/protocol/HeartbeatDiagnostics.java121
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/protocol/ProtocolBufferMonitorFilter.java115
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/security/AMQCallbackHandler.java30
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/security/CallbackHandlerRegistry.java231
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/security/CallbackHandlerRegistry.properties21
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/security/DynamicSaslRegistrar.java198
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/security/DynamicSaslRegistrar.properties20
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/security/JCAProvider.java71
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/security/UsernameHashedPasswordCallbackHandler.java102
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/security/UsernamePasswordCallbackHandler.java60
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/security/amqplain/AmqPlainSaslClient.java105
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/security/amqplain/AmqPlainSaslClientFactory.java63
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/security/crammd5hashed/CRAMMD5HashedSaslClientFactory.java72
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/state/AMQState.java56
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/state/AMQStateChangedEvent.java48
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/state/AMQStateListener.java26
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/state/AMQStateManager.java276
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/state/IllegalStateTransitionException.java53
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/state/StateAwareMethodListener.java36
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/state/StateListener.java30
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/state/StateWaiter.java122
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/state/listener/SpecificMethodFrameListener.java57
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/transport/AMQNoTransportForProtocolException.java62
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/transport/AMQTransportConnectionException.java41
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/transport/ITransportConnection.java32
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/transport/SocketTransportConnection.java101
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/transport/TransportConnection.java318
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/transport/VmPipeTransportConnection.java65
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/util/FlowControllingBlockingQueue.java109
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/client/vmbroker/AMQVMBrokerCreationException.java58
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/jms/BrokerDetails.java74
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/jms/ChannelLimitReachedException.java46
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/jms/Connection.java69
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/jms/ConnectionListener.java58
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/jms/ConnectionURL.java86
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/jms/FailoverPolicy.java324
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/jms/Message.java28
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/jms/MessageConsumer.java27
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/jms/MessageProducer.java53
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/jms/Session.java101
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/jms/failover/FailoverMethod.java76
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/jms/failover/FailoverRoundRobinServers.java261
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/jms/failover/FailoverSingleServer.java147
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/jndi/Example.properties39
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/jndi/NameParserImpl.java37
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/jndi/PropertiesFileInitialContextFactory.java337
-rw-r--r--Final/java/client/src/main/java/org/apache/qpid/jndi/ReadOnlyContext.java527
-rw-r--r--Final/java/client/src/old_test/java/org/apache/qpid/IBMPerfTest/JNDIBindConnectionFactory.java185
-rw-r--r--Final/java/client/src/old_test/java/org/apache/qpid/IBMPerfTest/JNDIBindQueue.java213
-rw-r--r--Final/java/client/src/old_test/java/org/apache/qpid/IBMPerfTest/JNDIBindTopic.java212
-rw-r--r--Final/java/client/src/old_test/java/org/apache/qpid/IBMPerfTest/README.txt11
-rw-r--r--Final/java/client/src/old_test/java/org/apache/qpid/cluster/Client.java129
-rw-r--r--Final/java/client/src/old_test/java/org/apache/qpid/codec/BasicDeliverTest.java277
-rw-r--r--Final/java/client/src/old_test/java/org/apache/qpid/codec/Client.java133
-rw-r--r--Final/java/client/src/old_test/java/org/apache/qpid/codec/Server.java103
-rw-r--r--Final/java/client/src/old_test/java/org/apache/qpid/config/AMQConnectionFactoryInitialiser.java35
-rw-r--r--Final/java/client/src/old_test/java/org/apache/qpid/config/AbstractConfig.java69
-rw-r--r--Final/java/client/src/old_test/java/org/apache/qpid/config/ConnectionFactoryInitialiser.java29
-rw-r--r--Final/java/client/src/old_test/java/org/apache/qpid/config/Connector.java40
-rw-r--r--Final/java/client/src/old_test/java/org/apache/qpid/config/ConnectorConfig.java28
-rw-r--r--Final/java/client/src/old_test/java/org/apache/qpid/config/JBossConnectionFactoryInitialiser.java111
-rw-r--r--Final/java/client/src/old_test/java/org/apache/qpid/flow/ChannelFlowTest.java112
-rw-r--r--Final/java/client/src/old_test/java/org/apache/qpid/fragmentation/TestLargePublisher.java196
-rw-r--r--Final/java/client/src/old_test/java/org/apache/qpid/fragmentation/TestLargeSubscriber.java167
-rw-r--r--Final/java/client/src/old_test/java/org/apache/qpid/headers/Listener.java117
-rw-r--r--Final/java/client/src/old_test/java/org/apache/qpid/headers/MessageFactory.java175
-rw-r--r--Final/java/client/src/old_test/java/org/apache/qpid/headers/Publisher.java133
-rw-r--r--Final/java/client/src/old_test/java/org/apache/qpid/jndi/referenceable/Bind.java273
-rw-r--r--Final/java/client/src/old_test/java/org/apache/qpid/jndi/referenceable/Lookup.java196
-rw-r--r--Final/java/client/src/old_test/java/org/apache/qpid/jndi/referenceable/Unbind.java166
-rw-r--r--Final/java/client/src/old_test/java/org/apache/qpid/latency/LatencyTest.java153
-rw-r--r--Final/java/client/src/old_test/java/org/apache/qpid/mina/AcceptorTest.java102
-rw-r--r--Final/java/client/src/old_test/java/org/apache/qpid/mina/BlockingAcceptorTest.java93
-rw-r--r--Final/java/client/src/old_test/java/org/apache/qpid/mina/WriterTest.java271
-rw-r--r--Final/java/client/src/old_test/java/org/apache/qpid/multiconsumer/AMQTest.java269
-rw-r--r--Final/java/client/src/old_test/java/org/apache/qpid/pubsub1/TestPublisher.java176
-rw-r--r--Final/java/client/src/old_test/java/org/apache/qpid/pubsub1/TestSubscriber.java122
-rw-r--r--Final/java/client/src/old_test/java/org/apache/qpid/test/unit/client/connection/TestManyConnections.java95
-rw-r--r--Final/java/client/src/old_test/java/org/apache/qpid/test/unit/jndi/PropertiesFileInitialContextFactoryTest.java153
-rw-r--r--Final/java/client/src/old_test/java/org/apache/qpid/test/unit/jndi/example.properties38
-rw-r--r--Final/java/client/src/old_test/java/org/apache/qpid/topic/Config.java243
-rw-r--r--Final/java/client/src/old_test/java/org/apache/qpid/topic/Listener.java141
-rw-r--r--Final/java/client/src/old_test/java/org/apache/qpid/topic/MessageFactory.java155
-rw-r--r--Final/java/client/src/old_test/java/org/apache/qpid/topic/Publisher.java175
-rw-r--r--Final/java/client/src/old_test/java/org/apache/qpid/transacted/Config.java110
-rw-r--r--Final/java/client/src/old_test/java/org/apache/qpid/transacted/Ping.java45
-rw-r--r--Final/java/client/src/old_test/java/org/apache/qpid/transacted/Pong.java45
-rw-r--r--Final/java/client/src/old_test/java/org/apache/qpid/transacted/Relay.java127
-rw-r--r--Final/java/client/src/old_test/java/org/apache/qpid/transacted/Start.java44
-rw-r--r--Final/java/client/src/old_test/java/org/apache/qpid/weblogic/ServiceProvider.java151
-rw-r--r--Final/java/client/src/old_test/java/org/apache/qpid/weblogic/ServiceRequestingClient.java185
-rw-r--r--Final/java/client/src/test/java/org/apache/mina/transport/vmpipe/support/VmPipeIdleStatusChecker.java125
-rw-r--r--Final/java/client/src/test/java/org/apache/qpid/client/AMQQueueDeferredOrderingTest.java152
-rw-r--r--Final/java/client/src/test/java/org/apache/qpid/client/DispatcherTest.java252
-rw-r--r--Final/java/client/src/test/java/org/apache/qpid/client/MessageListenerMultiConsumerImmediatePrefetch.java44
-rw-r--r--Final/java/client/src/test/java/org/apache/qpid/client/MessageListenerMultiConsumerTest.java252
-rw-r--r--Final/java/client/src/test/java/org/apache/qpid/client/MessageListenerTest.java195
-rw-r--r--Final/java/client/src/test/java/org/apache/qpid/client/ResetMessageListenerTest.java277
-rw-r--r--Final/java/client/src/test/java/org/apache/qpid/client/SpecificMethodFrameListenerTest.java71
-rw-r--r--Final/java/client/src/test/java/org/apache/qpid/client/message/NonQpidObjectMessage.java234
-rw-r--r--Final/java/client/src/test/java/org/apache/qpid/client/message/TestMessageHelper.java46
-rw-r--r--Final/java/client/src/test/java/org/apache/qpid/test/unit/ack/RecoverTest.java335
-rw-r--r--Final/java/client/src/test/java/org/apache/qpid/test/unit/basic/BytesMessageTest.java288
-rw-r--r--Final/java/client/src/test/java/org/apache/qpid/test/unit/basic/FieldTableKeyEnumeratorTest.java96
-rw-r--r--Final/java/client/src/test/java/org/apache/qpid/test/unit/basic/FieldTableMessageTest.java176
-rw-r--r--Final/java/client/src/test/java/org/apache/qpid/test/unit/basic/FieldTablePropertyTest.java62
-rw-r--r--Final/java/client/src/test/java/org/apache/qpid/test/unit/basic/InvalidDestinationTest.java130
-rw-r--r--Final/java/client/src/test/java/org/apache/qpid/test/unit/basic/LargeMessageTest.java194
-rw-r--r--Final/java/client/src/test/java/org/apache/qpid/test/unit/basic/MapMessageTest.java1277
-rw-r--r--Final/java/client/src/test/java/org/apache/qpid/test/unit/basic/MultipleConnectionTest.java231
-rw-r--r--Final/java/client/src/test/java/org/apache/qpid/test/unit/basic/ObjectMessageTest.java276
-rw-r--r--Final/java/client/src/test/java/org/apache/qpid/test/unit/basic/PropertyValueTest.java369
-rw-r--r--Final/java/client/src/test/java/org/apache/qpid/test/unit/basic/PubSubTwoConnectionTest.java77
-rw-r--r--Final/java/client/src/test/java/org/apache/qpid/test/unit/basic/ReceiveTest.java115
-rw-r--r--Final/java/client/src/test/java/org/apache/qpid/test/unit/basic/SelectorTest.java140
-rw-r--r--Final/java/client/src/test/java/org/apache/qpid/test/unit/basic/SessionStartTest.java122
-rw-r--r--Final/java/client/src/test/java/org/apache/qpid/test/unit/basic/TextMessageTest.java257
-rw-r--r--Final/java/client/src/test/java/org/apache/qpid/test/unit/basic/close/CloseTests.java80
-rw-r--r--Final/java/client/src/test/java/org/apache/qpid/test/unit/client/AMQConnectionTest.java205
-rw-r--r--Final/java/client/src/test/java/org/apache/qpid/test/unit/client/AMQSessionTest.java115
-rw-r--r--Final/java/client/src/test/java/org/apache/qpid/test/unit/client/BrokerDetails/BrokerDetailsTest.java94
-rw-r--r--Final/java/client/src/test/java/org/apache/qpid/test/unit/client/channelclose/ChannelCloseMethodHandlerNoCloseOk.java100
-rw-r--r--Final/java/client/src/test/java/org/apache/qpid/test/unit/client/channelclose/ChannelCloseOkTest.java235
-rw-r--r--Final/java/client/src/test/java/org/apache/qpid/test/unit/client/channelclose/ChannelCloseTest.java412
-rw-r--r--Final/java/client/src/test/java/org/apache/qpid/test/unit/client/channelclose/CloseWithBlockingReceiveTest.java87
-rw-r--r--Final/java/client/src/test/java/org/apache/qpid/test/unit/client/channelclose/NoCloseOKStateManager.java107
-rw-r--r--Final/java/client/src/test/java/org/apache/qpid/test/unit/client/connection/ConnectionStartTest.java175
-rw-r--r--Final/java/client/src/test/java/org/apache/qpid/test/unit/client/connection/ConnectionTest.java194
-rw-r--r--Final/java/client/src/test/java/org/apache/qpid/test/unit/client/connectionurl/ConnectionURLTest.java481
-rw-r--r--Final/java/client/src/test/java/org/apache/qpid/test/unit/client/destinationurl/DestinationURLTest.java145
-rw-r--r--Final/java/client/src/test/java/org/apache/qpid/test/unit/client/forwardall/Client.java123
-rw-r--r--Final/java/client/src/test/java/org/apache/qpid/test/unit/client/forwardall/CombinedTest.java68
-rw-r--r--Final/java/client/src/test/java/org/apache/qpid/test/unit/client/forwardall/Service.java84
-rw-r--r--Final/java/client/src/test/java/org/apache/qpid/test/unit/client/forwardall/ServiceCreator.java112
-rw-r--r--Final/java/client/src/test/java/org/apache/qpid/test/unit/client/forwardall/SpecialQueue.java46
-rw-r--r--Final/java/client/src/test/java/org/apache/qpid/test/unit/client/message/BytesMessageTest.java569
-rw-r--r--Final/java/client/src/test/java/org/apache/qpid/test/unit/client/message/MapMessageTest.java383
-rw-r--r--Final/java/client/src/test/java/org/apache/qpid/test/unit/client/message/ObjectMessageTest.java345
-rw-r--r--Final/java/client/src/test/java/org/apache/qpid/test/unit/client/message/StreamMessageTest.java623
-rw-r--r--Final/java/client/src/test/java/org/apache/qpid/test/unit/client/message/TextMessageTest.java300
-rw-r--r--Final/java/client/src/test/java/org/apache/qpid/test/unit/client/protocol/TestIoSession.java104
-rw-r--r--Final/java/client/src/test/java/org/apache/qpid/test/unit/client/temporaryqueue/TemporaryQueueTest.java232
-rw-r--r--Final/java/client/src/test/java/org/apache/qpid/test/unit/close/CloseBeforeAckTest.java147
-rw-r--r--Final/java/client/src/test/java/org/apache/qpid/test/unit/close/MessageRequeueTest.java389
-rw-r--r--Final/java/client/src/test/java/org/apache/qpid/test/unit/close/TopicPublisherCloseTest.java72
-rw-r--r--Final/java/client/src/test/java/org/apache/qpid/test/unit/message/JMSDestinationTest.java94
-rw-r--r--Final/java/client/src/test/java/org/apache/qpid/test/unit/message/JMSPropertiesTest.java108
-rw-r--r--Final/java/client/src/test/java/org/apache/qpid/test/unit/message/MessageConverterTest.java138
-rw-r--r--Final/java/client/src/test/java/org/apache/qpid/test/unit/message/NonQpidMessage.java411
-rw-r--r--Final/java/client/src/test/java/org/apache/qpid/test/unit/message/StreamMessageTest.java160
-rw-r--r--Final/java/client/src/test/java/org/apache/qpid/test/unit/topic/DurableSubscriptionTest.java192
-rw-r--r--Final/java/client/src/test/java/org/apache/qpid/test/unit/topic/TopicPublisherTest.java80
-rw-r--r--Final/java/client/src/test/java/org/apache/qpid/test/unit/topic/TopicSessionTest.java375
-rw-r--r--Final/java/client/src/test/java/org/apache/qpid/test/unit/transacted/CommitRollbackTest.java532
-rw-r--r--Final/java/client/src/test/java/org/apache/qpid/test/unit/transacted/TransactedTest.java313
-rw-r--r--Final/java/client/src/test/java/org/apache/qpid/testutil/Config.java199
-rw-r--r--Final/java/client/src/test/java/org/apache/qpid/testutil/QpidClientConnection.java287
-rw-r--r--Final/java/client/src/test/java/org/apache/qpid/testutil/VMBrokerSetup.java52
-rw-r--r--Final/java/client/test/bin/IBM-JNDI-Setup.bat69
-rwxr-xr-xFinal/java/client/test/bin/IBM-JNDI-Setup.sh27
-rw-r--r--Final/java/client/test/bin/IBM-Publisher.bat62
-rwxr-xr-xFinal/java/client/test/bin/IBM-Publisher.sh22
-rw-r--r--Final/java/client/test/bin/IBM-PutGet.bat62
-rwxr-xr-xFinal/java/client/test/bin/IBM-PutGet.sh21
-rw-r--r--Final/java/client/test/bin/IBM-README.txt19
-rw-r--r--Final/java/client/test/bin/IBM-Receiver.bat62
-rwxr-xr-xFinal/java/client/test/bin/IBM-Receiver.sh22
-rw-r--r--Final/java/client/test/bin/IBM-Sender.bat62
-rwxr-xr-xFinal/java/client/test/bin/IBM-Sender.sh22
-rw-r--r--Final/java/client/test/bin/IBM-Subscriber.bat62
-rwxr-xr-xFinal/java/client/test/bin/IBM-Subscriber.sh22
-rwxr-xr-xFinal/java/client/test/bin/headersListener.sh22
-rwxr-xr-xFinal/java/client/test/bin/headersListenerGroup.sh25
-rwxr-xr-xFinal/java/client/test/bin/headersPublisher.sh22
-rwxr-xr-xFinal/java/client/test/bin/run_many.sh30
-rwxr-xr-xFinal/java/client/test/bin/serviceProvidingClient.sh24
-rwxr-xr-xFinal/java/client/test/bin/serviceRequestingClient.sh27
-rwxr-xr-xFinal/java/client/test/bin/testService.sh22
-rwxr-xr-xFinal/java/client/test/bin/topicListener.sh23
-rwxr-xr-xFinal/java/client/test/bin/topicPublisher.sh22
-rw-r--r--Final/java/client/test/etc/ApacheDS.properties24
-rw-r--r--Final/java/client/test/example_build.xml104
296 files changed, 47791 insertions, 0 deletions
diff --git a/Final/java/client/distribution/pom.xml b/Final/java/client/distribution/pom.xml
new file mode 100644
index 0000000000..bd97463d15
--- /dev/null
+++ b/Final/java/client/distribution/pom.xml
@@ -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.
+ -->
+<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-M2</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-M2</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/Final/java/client/distribution/src/main/assembly/client-bin-tests.xml b/Final/java/client/distribution/src/main/assembly/client-bin-tests.xml
new file mode 100644
index 0000000000..ec4df1c9a7
--- /dev/null
+++ b/Final/java/client/distribution/src/main/assembly/client-bin-tests.xml
@@ -0,0 +1,107 @@
+<?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/Final/java/client/distribution/src/main/assembly/client-bin.xml b/Final/java/client/distribution/src/main/assembly/client-bin.xml
new file mode 100644
index 0000000000..70874b09a4
--- /dev/null
+++ b/Final/java/client/distribution/src/main/assembly/client-bin.xml
@@ -0,0 +1,78 @@
+<?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/Final/java/client/distribution/src/main/assembly/client-java1.4-bin.xml b/Final/java/client/distribution/src/main/assembly/client-java1.4-bin.xml
new file mode 100644
index 0000000000..6a2dd17c5c
--- /dev/null
+++ b/Final/java/client/distribution/src/main/assembly/client-java1.4-bin.xml
@@ -0,0 +1,74 @@
+<?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/Final/java/client/distribution/src/main/assembly/client-src.xml b/Final/java/client/distribution/src/main/assembly/client-src.xml
new file mode 100644
index 0000000000..b5055f05d7
--- /dev/null
+++ b/Final/java/client/distribution/src/main/assembly/client-src.xml
@@ -0,0 +1,62 @@
+<?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/Final/java/client/example/bin/set_classpath.bat b/Final/java/client/example/bin/set_classpath.bat
new file mode 100644
index 0000000000..d528967024
--- /dev/null
+++ b/Final/java/client/example/bin/set_classpath.bat
@@ -0,0 +1,50 @@
+@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 Helper script to set classpath for running Qpid example classes
+@REM NB: You must add the Qpid client and common jars to your CLASSPATH
+@REM before running this script
+
+@echo off
+
+if "%QPID_HOME%" == "" GOTO ERROR_QPID_HOME
+
+set QPIDLIB=%QPID_HOME%\lib
+
+if "%CLASSPATH%" == "" GOTO ERROR_CLASSPATH
+
+set CLASSPATH=%CLASSPATH%;%QPIDLIB%\backport-util-concurrent-2.2.jar
+set CLASSPATH=%CLASSPATH%;%QPIDLIB%\geronimo-jms_1.1_spec-1.0.jar
+set CLASSPATH=%CLASSPATH%;%QPIDLIB%\commons-collections-3.1.jar
+set CLASSPATH=%CLASSPATH%;%QPIDLIB%\commons-configuration-1.2.jar
+set CLASSPATH=%CLASSPATH%;%QPIDLIB%\commons-cli-1.0.jar
+set CLASSPATH=%CLASSPATH%;%QPIDLIB%\commons-lang-2.1.jar
+set CLASSPATH=%CLASSPATH%;%QPIDLIB%\commons-logging-api-1.0.4.jar
+set CLASSPATH=%CLASSPATH%;%QPIDLIB%\commons-logging-1.0.jar
+set CLASSPATH=%CLASSPATH%;%QPIDLIB%\log4j-1.2.12.jar
+set CLASSPATH=%CLASSPATH%;%QPIDLIB%\mina-core-1.0.0.jar
+set CLASSPATH=%CLASSPATH%;%QPIDLIB%\mina-filter-ssl-1.0.0.jar
+set CLASSPATH=%CLASSPATH%;%QPIDLIB%\mina-java5-1.0.0.jar
+set CLASSPATH=%CLASSPATH%;%QPIDLIB%\slf4j-simple-1.0.jar
+
+GOTO END
+
+:ERROR_CLASSPATH
+Echo Please set set your CLASSPATH variable to include the Qpid client and common jars. Exiting ....
+:ERROR_QPID_HOME
+Echo Please set QPID_HOME variable. Exiting ....
+:END
diff --git a/Final/java/client/example/bin/set_classpath.sh b/Final/java/client/example/bin/set_classpath.sh
new file mode 100755
index 0000000000..89e9bc8242
--- /dev/null
+++ b/Final/java/client/example/bin/set_classpath.sh
@@ -0,0 +1,83 @@
+#!/bin/sh -xv
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+# Helper script to set classpath for running Qpid example classes
+# NB: You must add the Qpid client and common jars to your CLASSPATH
+# before running this script
+
+
+cygwin=false
+if [[ "$(uname -a | fgrep Cygwin)" != "" ]]; then
+ cygwin=true
+fi
+
+#Should have set the QPID_HOME var after install to the working dir e.g. home/qpid/qpid-1.0-incubating-M2-SNAPSHOT
+if [ "$QPID_HOME" = "" ] ; then
+ echo "ERROR: Please set QPID_HOME variable. Exiting ...."
+ exit 1
+else
+ QPIDLIB=$QPID_HOME/lib
+fi
+
+if $cygwin; then
+ QPIDLIB=$(cygpath -w $QPIDLIB)
+fi
+
+if [ "$CLASSPATH" = "" ] ; then
+ echo "ERROR: Please set set your CLASSPATH variable to include the Qpid client and common jars. Exiting ...."
+ exit 2
+fi
+
+#Converts paths for cygwin if req
+#Some nasty concatenation to get round cygpath line limits
+if $cygwin; then
+ SEP=";"
+ CLASSPATH=`cygpath -w $CLASSPATH`
+ CLASSPATH=$CLASSPATH$SEP`cygpath -w $QPIDLIB/backport-util-concurrent-2.2.jar`
+ CLASSPATH=$CLASSPATH$SEP`cygpath -w $QPIDLIB/geronimo-jms_1.1_spec-1.0.jar`
+ CLASSPATH=$CLASSPATH$SEP`cygpath -w $QPIDLIB/commons-collections-3.1.jar`
+ CLASSPATH=$CLASSPATH$SEP`cygpath -w $QPIDLIB/commons-configuration-1.2.jar`
+ CLASSPATH=$CLASSPATH$SEP`cygpath -w $QPIDLIB/commons-cli-1.0.jar`
+ CLASSPATH=$CLASSPATH$SEP`cygpath -w $QPIDLIB/commons-lang-2.1.jar`
+ CLASSPATH=$CLASSPATH$SEP`cygpath -w $QPIDLIB/commons-logging-api-1.0.4.jar`
+ CLASSPATH=$CLASSPATH$SEP`cygpath -w $QPIDLIB/commons-logging-1.0.jar`
+ CLASSPATH=$CLASSPATH$SEP`cygpath -w $QPIDLIB/log4j-1.2.12.jar`
+ CLASSPATH=$CLASSPATH$SEP`cygpath -w $QPIDLIB/mina-core-1.0.0.jar`
+ CLASSPATH=$CLASSPATH$SEP`cygpath -w $QPIDLIB/mina-filter-ssl-1.0.0.jar`
+ CLASSPATH=$CLASSPATH$SEP`cygpath -w $QPIDLIB/mina-java5-1.0.0.jar`
+ CLASSPATH=$CLASSPATH$SEP`cygpath -w $QPIDLIB/slf4j-simple-1.0.jar`
+ export CLASSPATH
+else
+ CLASSPATH=$CLASSPATH:$QPIDLIB/backport-util-concurrent-2.2.jar
+ CLASSPATH=$CLASSPATH:$QPIDLIB/geronimo-jms_1.1_spec-1.0.jar
+ CLASSPATH=$CLASSPATH:$QPIDLIB/commons-collections-3.1.jar
+ CLASSPATH=$CLASSPATH:$QPIDLIB/commons-configuration-1.2.jar
+ CLASSPATH=$CLASSPATH:$QPIDLIB/commons-cli-1.0.jar
+ CLASSPATH=$CLASSPATH:$QPIDLIB/commons-lang-2.1.jar
+ CLASSPATH=$CLASSPATH:$QPIDLIB/commons-logging-api-1.0.4.jar
+ CLASSPATH=$CLASSPATH:$QPIDLIB/commons-logging-1.0.jar
+ CLASSPATH=$CLASSPATH:$QPIDLIB/log4j-1.2.12.jar
+ CLASSPATH=$CLASSPATH:$QPIDLIB/mina-core-1.0.0.jar
+ CLASSPATH=$CLASSPATH:$QPIDLIB/mina-filter-ssl-1.0.0.jar
+ CLASSPATH=$CLASSPATH:$QPIDLIB/mina-java5-1.0.0.jar
+ CLASSPATH=$CLASSPATH:$QPIDLIB/slf4j-simple-1.0.jar
+ export CLASSPATH
+fi
+
diff --git a/Final/java/client/example/pom.xml b/Final/java/client/example/pom.xml
new file mode 100644
index 0000000000..3d4cf21a2d
--- /dev/null
+++ b/Final/java/client/example/pom.xml
@@ -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.
+-->
+<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-M2</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-M2</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/Final/java/client/example/source-jar.xml b/Final/java/client/example/source-jar.xml
new file mode 100644
index 0000000000..60451448b8
--- /dev/null
+++ b/Final/java/client/example/source-jar.xml
@@ -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.
+-->
+<!-- This is an assembly descriptor that produces a jar file that contains all the
+ dependencies, fully expanded into a single jar, required to run the tests of
+ a maven project.
+ -->
+<assembly>
+ <id>source</id>
+ <formats>
+ <format>jar</format>
+ </formats>
+ <includeBaseDirectory>false</includeBaseDirectory>
+ <fileSets>
+ <fileSet>
+ <directory>src/main/java</directory>
+ <outputDirectory></outputDirectory>
+ </fileSet>
+ </fileSets>
+</assembly>
diff --git a/Final/java/client/example/src/main/java/org/apache/qpid/example/log4j.xml b/Final/java/client/example/src/main/java/org/apache/qpid/example/log4j.xml
new file mode 100644
index 0000000000..de64423a51
--- /dev/null
+++ b/Final/java/client/example/src/main/java/org/apache/qpid/example/log4j.xml
@@ -0,0 +1,45 @@
+<?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.
+ -
+ -->
+<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
+<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
+ <appender name="FileAppender" class="org.apache.log4j.FileAppender">
+ <param name="File" value="ams_messaging.log"/>
+ <param name="Append" value="false"/>
+
+ <layout class="org.apache.log4j.PatternLayout">
+ <param name="ConversionPattern" value="%t %-5p %c{2} - %m%n"/>
+ </layout>
+ </appender>
+
+ <appender name="STDOUT" class="org.apache.log4j.ConsoleAppender">
+
+ <layout class="org.apache.log4j.PatternLayout">
+ <param name="ConversionPattern" value="%d %-5p [%t] %C{2} (%F:%L) - %m%n"/>
+ </layout>
+ </appender>
+
+ <root>
+ <priority value="debug"/>
+ <appender-ref ref="STDOUT"/>
+ <appender-ref ref="FileAppender"/>
+ </root>
+</log4j:configuration> \ No newline at end of file
diff --git a/Final/java/client/example/src/main/java/org/apache/qpid/example/publisher/FileMessageDispatcher.java b/Final/java/client/example/src/main/java/org/apache/qpid/example/publisher/FileMessageDispatcher.java
new file mode 100644
index 0000000000..6a7626c51d
--- /dev/null
+++ b/Final/java/client/example/src/main/java/org/apache/qpid/example/publisher/FileMessageDispatcher.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.example.publisher;
+
+import java.io.File;
+
+import javax.jms.JMSException;
+
+import org.apache.log4j.Logger;
+
+import org.apache.qpid.example.shared.FileUtils;
+import org.apache.qpid.example.shared.Statics;
+
+/**
+ * Class that sends message files to the Publisher to distribute
+ * using files as input
+ * Must set properties for host in properties file or uses in vm broker
+ */
+public class FileMessageDispatcher
+{
+
+ protected static final Logger _logger = Logger.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 == 0)
+ {
+ System.out.println("Usage: FileMessageDispatcher <filesToDispatch>" + "");
+ }
+ else
+ {
+ try
+ {
+ // publish message(s) from file(s) to configured queue
+ publish(args[0]);
+
+ // 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
+ {
+ // clean up before exiting
+ if (getPublisher() != null)
+ {
+ getPublisher().cleanup();
+ }
+ }
+ }
+
+ 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 path - from main args
+ * @throws JMSException
+ * @throws MessageFactoryException - if cannot create message from file content
+ */
+ public static void publish(String path) throws JMSException, MessageFactoryException
+ {
+ File tempFile = new File(path);
+ if (tempFile.isDirectory())
+ {
+ // while more files in dir publish them
+ File[] files = tempFile.listFiles();
+
+ if ((files == null) || (files.length == 0))
+ {
+ _logger.info("FileMessageDispatcher - No files to publish in input directory: " + tempFile);
+ }
+ else
+ {
+ for (File file : files)
+ {
+ // Create message factory passing in payload path
+ FileMessageFactory factory = new FileMessageFactory(getPublisher().getSession(), file.toString());
+
+ // Send the message generated from the payload using the _publisher
+ getPublisher().sendMessage(factory.createEventMessage());
+
+ }
+ }
+ }
+ else
+ {
+ // handle a single file
+ // Create message factory passing in payload path
+ FileMessageFactory factory = new FileMessageFactory(getPublisher().getSession(), tempFile.toString());
+
+ // Send the message generated from the payload using the _publisher
+ getPublisher().sendMessage(factory.createEventMessage());
+ }
+ }
+
+ /**
+ * Cleanup before exit
+ */
+ public static void cleanup()
+ {
+ if (getPublisher() != null)
+ {
+ getPublisher().cleanup();
+ }
+ }
+
+ /**
+ * @return A Publisher instance
+ */
+ private static Publisher getPublisher()
+ {
+ if (_publisher != null)
+ {
+ return _publisher;
+ }
+
+ // Create a _publisher
+ _publisher = new Publisher();
+
+ return _publisher;
+ }
+
+}
diff --git a/Final/java/client/example/src/main/java/org/apache/qpid/example/publisher/FileMessageFactory.java b/Final/java/client/example/src/main/java/org/apache/qpid/example/publisher/FileMessageFactory.java
new file mode 100644
index 0000000000..f3b21e3c64
--- /dev/null
+++ b/Final/java/client/example/src/main/java/org/apache/qpid/example/publisher/FileMessageFactory.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.example.publisher;
+
+import org.apache.qpid.example.shared.FileUtils;
+import org.apache.qpid.example.shared.Statics;
+
+import java.io.*;
+import javax.jms.*;
+
+public class FileMessageFactory
+{
+ protected final Session _session;
+ protected final String _payload;
+ protected final String _filename;
+
+ /**
+ * Contructs and instance using a filename from which content will be used to create message
+ * @param session
+ * @param filename
+ * @throws MessageFactoryException
+ */
+ public FileMessageFactory(Session session, String filename) throws MessageFactoryException
+ {
+ try
+ {
+ _filename = filename;
+ _payload = FileUtils.getFileContent(filename);
+ _session = session;
+ }
+ catch (IOException e)
+ {
+ MessageFactoryException mfe = new MessageFactoryException(e.toString());
+ mfe.initCause(e);
+ throw mfe;
+ }
+ }
+
+ /**
+ * Creates a text message and sets filename property on it
+ * The filename property is purely intended to provide visibility
+ * of file content passing trhough the broker using example classes
+ * @return Message - a TextMessage with content from file
+ * @throws JMSException
+ */
+ public Message createEventMessage() throws JMSException
+ {
+ TextMessage msg = _session.createTextMessage();
+ msg.setText(_payload);
+ msg.setStringProperty(Statics.FILENAME_PROPERTY,new File(_filename).getName());
+ return msg;
+ }
+
+ /**
+ * Creates message from a string for use by the monitor
+ * @param session
+ * @param textMsg - message content
+ * @return Message - TextMessage with content from String
+ * @throws JMSException
+ */
+ public static Message createSimpleEventMessage(Session session, String textMsg) throws JMSException
+ {
+ TextMessage msg = session.createTextMessage();
+ msg.setText(textMsg);
+ return msg;
+ }
+
+ public Message createShutdownMessage() throws JMSException
+ {
+ return _session.createTextMessage("SHUTDOWN");
+ }
+
+ public Message createReportRequestMessage() throws JMSException
+ {
+ return _session.createTextMessage("REPORT");
+ }
+
+ public Message createReportResponseMessage(String msg) throws JMSException
+ {
+ return _session.createTextMessage(msg);
+ }
+
+ public boolean isShutdown(Message m)
+ {
+ return checkText(m, "SHUTDOWN");
+ }
+
+ public boolean isReport(Message m)
+ {
+ return checkText(m, "REPORT");
+ }
+
+ public Object getReport(Message m)
+ {
+ try
+ {
+ return ((TextMessage) m).getText();
+ }
+ catch (JMSException e)
+ {
+ e.printStackTrace(System.out);
+ return e.toString();
+ }
+ }
+
+ private static boolean checkText(Message m, String s)
+ {
+ try
+ {
+ return m instanceof TextMessage && ((TextMessage) m).getText().equals(s);
+ }
+ catch (JMSException e)
+ {
+ e.printStackTrace(System.out);
+ return false;
+ }
+ }
+}
+
diff --git a/Final/java/client/example/src/main/java/org/apache/qpid/example/publisher/MessageFactoryException.java b/Final/java/client/example/src/main/java/org/apache/qpid/example/publisher/MessageFactoryException.java
new file mode 100644
index 0000000000..0a4231c977
--- /dev/null
+++ b/Final/java/client/example/src/main/java/org/apache/qpid/example/publisher/MessageFactoryException.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.example.publisher;
+
+public class MessageFactoryException extends Exception
+{
+
+ private int _errorCode;
+
+ public MessageFactoryException(String message)
+ {
+ super(message);
+ }
+
+ public MessageFactoryException(String msg, Throwable t)
+ {
+ super(msg, t);
+ }
+
+ public MessageFactoryException(int errorCode, String msg, Throwable t)
+ {
+ super(msg + " [error code " + errorCode + ']', t);
+ _errorCode = errorCode;
+ }
+
+ public MessageFactoryException(int errorCode, String msg)
+ {
+ super(msg + " [error code " + errorCode + ']');
+ _errorCode = errorCode;
+ }
+
+ public int getErrorCode()
+ {
+ return _errorCode;
+ }
+}
diff --git a/Final/java/client/example/src/main/java/org/apache/qpid/example/publisher/MonitorMessageDispatcher.java b/Final/java/client/example/src/main/java/org/apache/qpid/example/publisher/MonitorMessageDispatcher.java
new file mode 100644
index 0000000000..b6544db995
--- /dev/null
+++ b/Final/java/client/example/src/main/java/org/apache/qpid/example/publisher/MonitorMessageDispatcher.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 org.apache.log4j.BasicConfigurator;
+import org.apache.log4j.Logger;
+
+import javax.jms.DeliveryMode;
+import javax.jms.JMSException;
+
+/**
+ * Class that sends heartbeat messages to allow monitoring of message consumption Sends regular (currently 20 seconds
+ * apart) heartbeat message
+ */
+public class MonitorMessageDispatcher
+{
+
+ private static final Logger _logger = Logger.getLogger(MonitorMessageDispatcher.class);
+
+ protected static MonitorPublisher _monitorPublisher = null;
+
+ protected static final String DEFAULT_MONITOR_PUB_NAME = "MonitorPublisher";
+
+ /**
+ * Easy entry point for running a message dispatcher for monitoring consumption
+ *
+ * @param args
+ */
+ public static void main(String[] args)
+ {
+ //Switch on logging appropriately for your app
+ BasicConfigurator.configure();
+
+ try
+ {
+ int i =0;
+ while (i < 1000)
+ {
+ try
+ {
+ //endlessly publish messages to monitor queue
+ publish();
+
+ if (_logger.isDebugEnabled())
+ {
+ _logger.debug("Dispatched monitor message");
+ }
+
+ //sleep for twenty seconds and then publish again - change if appropriate
+ //Thread.sleep(1000);
+ i++ ;
+ }
+ catch (UndeliveredMessageException a)
+ {
+ //trigger application specific failure handling here
+ _logger.error("Problem delivering monitor message");
+ break;
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ _logger.error("Error trying to dispatch AMS monitor message: " + e);
+ System.exit(1);
+ }
+ finally
+ {
+ if (getMonitorPublisher() != null)
+ {
+ getMonitorPublisher().cleanup();
+ }
+ }
+
+ System.exit(1);
+ }
+
+ /**
+ * Publish heartbeat message
+ *
+ * @throws JMSException
+ * @throws UndeliveredMessageException
+ */
+ public static void publish() throws JMSException, UndeliveredMessageException
+ {
+ //Send the message generated from the payload using the _publisher
+// getMonitorPublisher().sendImmediateMessage
+// (FileMessageFactory.createSimpleEventMessage(getMonitorPublisher().getSession(),"monitor:" +System.currentTimeMillis()));
+
+ getMonitorPublisher().sendMessage
+ (getMonitorPublisher()._session,
+ FileMessageFactory.createSimpleEventMessage(getMonitorPublisher().getSession(), "monitor:" + System.currentTimeMillis()),
+ DeliveryMode.PERSISTENT, false, true);
+
+ }
+
+ /** Cleanup publishers */
+ public static void cleanup()
+ {
+ if (getMonitorPublisher() != null)
+ {
+ getMonitorPublisher().cleanup();
+ }
+
+ if (getMonitorPublisher() != null)
+ {
+ getMonitorPublisher().cleanup();
+ }
+ }
+
+ //Returns a _publisher for the monitor queue
+ private static MonitorPublisher getMonitorPublisher()
+ {
+ if (_monitorPublisher != null)
+ {
+ return _monitorPublisher;
+ }
+
+ //Create a _publisher using failover details and constant for monitor queue
+ _monitorPublisher = new MonitorPublisher();
+
+ _monitorPublisher.setName(MonitorMessageDispatcher.DEFAULT_MONITOR_PUB_NAME);
+ return _monitorPublisher;
+ }
+
+}
diff --git a/Final/java/client/example/src/main/java/org/apache/qpid/example/publisher/MonitorPublisher.java b/Final/java/client/example/src/main/java/org/apache/qpid/example/publisher/MonitorPublisher.java
new file mode 100644
index 0000000000..a67b602e58
--- /dev/null
+++ b/Final/java/client/example/src/main/java/org/apache/qpid/example/publisher/MonitorPublisher.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.example.publisher;
+
+import org.apache.log4j.Logger;
+import org.apache.qpid.client.BasicMessageProducer;
+
+import javax.jms.DeliveryMode;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.Session;
+
+/**
+ * Subclass of Publisher which uses QPID functionality to send a heartbeat message Note immediate flag not available via
+ * JMS MessageProducer
+ */
+public class MonitorPublisher extends Publisher
+{
+
+ private static final Logger _log = Logger.getLogger(Publisher.class);
+
+ BasicMessageProducer _producer;
+
+ public MonitorPublisher()
+ {
+ super();
+ }
+
+ /*
+ * Publishes a message using given details
+ */
+ public boolean sendMessage(Session session, Message message, int deliveryMode,
+ boolean immediate, boolean commit) throws UndeliveredMessageException
+ {
+ try
+ {
+ _producer = (BasicMessageProducer) session.createProducer(_destination);
+
+ _producer.send(message, deliveryMode, immediate);
+
+ if (commit)
+ {
+ //commit the message send and close the transaction
+ _session.commit();
+ }
+
+ }
+ catch (JMSException e)
+ {
+ //Have to assume our commit failed but do not rollback here as channel closed
+ _log.error(e);
+ e.printStackTrace();
+ throw new UndeliveredMessageException("Cannot deliver immediate message", e);
+ }
+
+ _log.info(_name + " finished sending message: " + message);
+ return true;
+ }
+
+ /*
+ * Publishes a non-persistent message using transacted session
+ */
+ public boolean sendImmediateMessage(Message message) throws UndeliveredMessageException
+ {
+ try
+ {
+ _producer = (BasicMessageProducer) _session.createProducer(_destination);
+
+ //Send message via our producer which is not persistent and is immediate
+ //NB: not available via jms interface MessageProducer
+ _producer.send(message, DeliveryMode.NON_PERSISTENT, true);
+
+ //commit the message send and close the transaction
+ _session.commit();
+
+ }
+ catch (JMSException e)
+ {
+ //Have to assume our commit failed but do not rollback here as channel closed
+ _log.error(e);
+ e.printStackTrace();
+ throw new UndeliveredMessageException("Cannot deliver immediate message", e);
+ }
+
+ _log.info(_name + " finished sending message: " + message);
+ return true;
+ }
+}
diff --git a/Final/java/client/example/src/main/java/org/apache/qpid/example/publisher/Publisher.java b/Final/java/client/example/src/main/java/org/apache/qpid/example/publisher/Publisher.java
new file mode 100644
index 0000000000..2bde4ec35c
--- /dev/null
+++ b/Final/java/client/example/src/main/java/org/apache/qpid/example/publisher/Publisher.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.example.publisher;
+
+import org.apache.log4j.Logger;
+
+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.naming.InitialContext;
+
+import org.apache.qpid.example.shared.InitialContextHelper;
+
+public class Publisher
+{
+ private static final Logger _log = Logger.getLogger(Publisher.class);
+
+ protected InitialContextHelper _contextHelper;
+
+ protected Connection _connection;
+
+ protected Session _session;
+
+ protected MessageProducer _producer;
+
+ protected String _destinationDir;
+
+ protected String _name = "Publisher";
+
+ protected Queue _destination;
+
+ protected static final String _defaultDestinationDir = "/tmp";
+
+ /**
+ * Creates a Publisher instance using properties from example.properties
+ * See InitialContextHelper for details of how context etc created
+ */
+ public Publisher()
+ {
+ try
+ {
+ //get an initial context from default properties
+ _contextHelper = new InitialContextHelper(null);
+ InitialContext ctx = _contextHelper.getInitialContext();
+
+ //then create a connection using the AMQConnectionFactory
+ AMQConnectionFactory cf = (AMQConnectionFactory) ctx.lookup("local");
+ _connection = cf.createConnection();
+
+ //create a transactional session
+ _session = _connection.createSession(true, Session.AUTO_ACKNOWLEDGE);
+
+ //lookup the example queue and use it
+ //Queue is non-exclusive and not deleted when last consumer detaches
+ _destination = (Queue) ctx.lookup("MyQueue");
+
+ //create a message producer
+ _producer = _session.createProducer(_destination);
+
+ //set destination dir for files that have been processed
+ _destinationDir = _defaultDestinationDir;
+
+ _connection.start();
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ _log.error(e);
+ }
+ }
+
+ /**
+ * Publishes a non-persistent message using transacted session
+ * Note that persistent is the default mode for send - so need to specify for transient
+ */
+ public boolean sendMessage(Message message)
+ {
+ try
+ {
+ //Send message via our producer which is not persistent
+ _producer.send(message, DeliveryMode.NON_PERSISTENT, _producer.getPriority(), _producer.getTimeToLive());
+
+ //commit the message send and close the transaction
+ _session.commit();
+
+ }
+ catch (JMSException e)
+ {
+ //Have to assume our commit failed and rollback here
+ try
+ {
+ _session.rollback();
+ _log.error(e);
+ e.printStackTrace();
+ return false;
+ }
+ catch (JMSException j)
+ {
+ _log.error("Unable to rollback publish transaction ",e);
+ return false;
+ }
+ }
+
+ _log.info(_name + " finished sending message: " + message);
+ return true;
+ }
+
+ /**
+ * Cleanup resources before exit
+ */
+ public void cleanup()
+ {
+ try
+ {
+ if (_connection != null)
+ {
+ _connection.stop();
+ _connection.close();
+ }
+ _connection = null;
+ _producer = null;
+ }
+ catch(Exception e)
+ {
+ _log.error("Error trying to cleanup publisher " + e);
+ System.exit(1);
+ }
+ }
+
+ /**
+ * Exposes session
+ * @return Session
+ */
+ public Session getSession()
+ {
+ return _session;
+ }
+
+ public String getDestinationDir()
+ {
+ return _destinationDir;
+ }
+
+ public void setDestinationDir(String destinationDir)
+ {
+ _destinationDir = destinationDir;
+ }
+
+ public String getName()
+ {
+ return _name;
+ }
+
+ public void setName(String _name) {
+ this._name = _name;
+ }
+}
+
diff --git a/Final/java/client/example/src/main/java/org/apache/qpid/example/publisher/UndeliveredMessageException.java b/Final/java/client/example/src/main/java/org/apache/qpid/example/publisher/UndeliveredMessageException.java
new file mode 100644
index 0000000000..399cbc9427
--- /dev/null
+++ b/Final/java/client/example/src/main/java/org/apache/qpid/example/publisher/UndeliveredMessageException.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.example.publisher;
+
+/**
+ * Exception thrown by monitor when cannot send a message marked for immediate delivery
+ */
+public class UndeliveredMessageException extends Exception
+{
+
+ private int _errorCode;
+
+ public UndeliveredMessageException(String message)
+ {
+ super(message);
+ }
+
+ public UndeliveredMessageException(String msg, Throwable t)
+ {
+ super(msg, t);
+ }
+
+ public UndeliveredMessageException(int errorCode, String msg, Throwable t)
+ {
+ super(msg + " [error code " + errorCode + ']', t);
+ _errorCode = errorCode;
+ }
+
+ public UndeliveredMessageException(int errorCode, String msg)
+ {
+ super(msg + " [error code " + errorCode + ']');
+ _errorCode = errorCode;
+ }
+
+ public int getErrorCode()
+ {
+ return _errorCode;
+ }
+}
diff --git a/Final/java/client/example/src/main/java/org/apache/qpid/example/pubsub/Client.java b/Final/java/client/example/src/main/java/org/apache/qpid/example/pubsub/Client.java
new file mode 100644
index 0000000000..e32ee0ba73
--- /dev/null
+++ b/Final/java/client/example/src/main/java/org/apache/qpid/example/pubsub/Client.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.example.pubsub;
+
+import javax.jms.Connection;
+import javax.jms.Destination;
+import javax.jms.JMSException;
+import javax.jms.Session;
+import javax.naming.NamingException;
+
+/**
+ * An abstract base class that wraps up the creation of a JMS client utilising JNDI
+ */
+public abstract class Client
+{
+ protected ConnectionSetup _setup;
+
+ protected Connection _connection;
+ protected Destination _destination;
+ protected Session _session;
+
+ public Client(String destination)
+ {
+ if (destination == null)
+ {
+ destination = ConnectionSetup.TOPIC_JNDI_NAME;
+ }
+
+ try
+ {
+ _setup = new ConnectionSetup();
+ }
+ catch (NamingException e)
+ {
+ //ignore
+ }
+
+ if (_setup != null)
+ {
+ try
+ {
+ _connection = _setup.getConnectionFactory().createConnection();
+ _destination = _setup.getDestination(destination);
+ }
+ catch (JMSException e)
+ {
+ System.err.println(e.getMessage());
+ }
+ }
+ }
+
+ public abstract void start();
+
+} \ No newline at end of file
diff --git a/Final/java/client/example/src/main/java/org/apache/qpid/example/pubsub/ConnectionSetup.java b/Final/java/client/example/src/main/java/org/apache/qpid/example/pubsub/ConnectionSetup.java
new file mode 100644
index 0000000000..c4edd9034f
--- /dev/null
+++ b/Final/java/client/example/src/main/java/org/apache/qpid/example/pubsub/ConnectionSetup.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.example.pubsub;
+
+import javax.jms.ConnectionFactory;
+import javax.jms.Destination;
+import javax.naming.Context;
+import javax.naming.InitialContext;
+import javax.naming.NamingException;
+import java.util.Properties;
+
+/**
+ * This ConnectionSetup is a wrapper around JNDI it creates a number of entries.
+ *
+ * It is equivalent to a PropertyFile of value:
+ *
+ * connectionfactory.local=amqp://guest:guest@clientid/test?brokerlist='localhost'
+ * connectionfactory.vm=amqp://guest:guest@clientid/test?brokerlist='vm://:1'
+ *
+ * queue.queue=example.MyQueue
+ * topic.topic=example.hierarical.topic
+ *
+ */
+public class ConnectionSetup
+{
+ final static String INITIAL_CONTEXT_FACTORY = "org.apache.qpid.jndi.PropertiesFileInitialContextFactory";
+
+ final static String CONNECTION_JNDI_NAME = "local";
+ final static String CONNECTION_NAME = "amqp://guest:guest@clientid/test?brokerlist='localhost'";
+
+ public static final String QUEUE_JNDI_NAME = "queue";
+ final static String QUEUE_NAME = "example.MyQueue";
+
+ public static final String TOPIC_JNDI_NAME = "topic";
+ final static String TOPIC_NAME = "example.hierarical.topic";
+
+ private Context _ctx;
+
+ public ConnectionSetup() throws NamingException
+ {
+
+ // 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("connectionfactory." + "vm", "amqp://guest:guest@clientid/test?brokerlist='vm://:1'");
+
+ properties.put("queue." + QUEUE_JNDI_NAME, QUEUE_NAME);
+ properties.put("topic." + TOPIC_JNDI_NAME, TOPIC_NAME);
+ // Create the initial context
+ _ctx = new InitialContext(properties);
+
+ }
+
+ public ConnectionSetup(Properties properties) throws NamingException
+ {
+ _ctx = new InitialContext(properties);
+ }
+
+ public ConnectionFactory getConnectionFactory()
+ {
+
+ // Perform the lookups
+ try
+ {
+ return (ConnectionFactory) _ctx.lookup(CONNECTION_JNDI_NAME);
+ }
+ catch (NamingException e)
+ {
+ //ignore
+ }
+ return null;
+ }
+
+ public Destination getDestination(String jndiName)
+ {
+ // Perform the lookups
+ try
+ {
+ return (Destination) _ctx.lookup(jndiName);
+ }
+ catch (ClassCastException cce)
+ {
+ //ignore
+ }
+ catch (NamingException ne)
+ {
+ //ignore
+ }
+ return null;
+ }
+
+
+ public void close()
+ {
+ try
+ {
+ _ctx.close();
+ }
+ catch (NamingException e)
+ {
+ //ignore
+ }
+ }
+}
diff --git a/Final/java/client/example/src/main/java/org/apache/qpid/example/pubsub/Publisher.java b/Final/java/client/example/src/main/java/org/apache/qpid/example/pubsub/Publisher.java
new file mode 100644
index 0000000000..dd936e429f
--- /dev/null
+++ b/Final/java/client/example/src/main/java/org/apache/qpid/example/pubsub/Publisher.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.example.pubsub;
+
+import javax.jms.JMSException;
+import javax.jms.MessageProducer;
+import javax.jms.Session;
+
+/**
+ * A simple Publisher example.
+ *
+ * The class can take two arguments.
+ * java Publisher <destination> <msgCount>
+ * Where:
+ * destination is either 'topic' or 'queue' (Default: topic)
+ * msgCount is the number of messages to send (Default : 100)
+ *
+ */
+public class Publisher extends Client
+{
+ int _msgCount;
+
+ public Publisher(String destination, int msgCount)
+ {
+ super(destination);
+ _msgCount = msgCount;
+ }
+
+ public void start()
+ {
+ try
+ {
+ _session = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ MessageProducer _producer = _session.createProducer(_destination);
+
+ for (int msgCount = 0; msgCount < _msgCount; msgCount++)
+ {
+ _producer.send(_session.createTextMessage("msg:" + msgCount));
+ System.out.println("Sent:" + msgCount);
+ }
+
+ System.out.println("Done.");
+ _connection.close();
+ }
+ catch (JMSException e)
+ {
+ e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
+ }
+ }
+
+
+ public static void main(String[] args)
+ {
+
+ String destination = args.length > 2 ? args[1] : null;
+
+ int msgCount = args.length > 2 ? Integer.parseInt(args[2]) : 100;
+
+ new Publisher(destination, msgCount).start();
+ }
+
+}
diff --git a/Final/java/client/example/src/main/java/org/apache/qpid/example/pubsub/Subscriber.java b/Final/java/client/example/src/main/java/org/apache/qpid/example/pubsub/Subscriber.java
new file mode 100644
index 0000000000..f2d736701f
--- /dev/null
+++ b/Final/java/client/example/src/main/java/org/apache/qpid/example/pubsub/Subscriber.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.example.pubsub;
+
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageListener;
+import javax.jms.Session;
+import javax.jms.TextMessage;
+import javax.jms.Topic;
+import java.util.concurrent.CountDownLatch;
+
+
+/**
+ * Simple client that listens for the specified number of msgs on the given Destinaton
+ *
+ * The class can take two arguments.
+ * java Subscriber <destination> <msgCount>
+ * Where:
+ * destination is either 'topic' or 'queue' (Default: topic)
+ * msgCount is the number of messages to send (Default : 100)
+ */
+public class Subscriber extends Client implements MessageListener
+{
+
+ CountDownLatch _count;
+
+ public Subscriber(String destination, int msgCount)
+ {
+ super(destination);
+ _count = new CountDownLatch(msgCount);
+ }
+
+
+ public void start()
+ {
+ try
+ {
+ _session = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ _session.createDurableSubscriber((Topic) _setup.getDestination(ConnectionSetup.TOPIC_JNDI_NAME),
+ "exampleClient").setMessageListener(this);
+ _connection.start();
+ _count.await();
+
+ System.out.println("Done");
+
+ _connection.close();
+ }
+ catch (JMSException e)
+ {
+ e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
+ }
+ catch (InterruptedException e)
+ {
+ e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
+ }
+ }
+
+ public static void main(String[] args)
+ {
+ String destination = args.length > 2 ? args[1] : null;
+ int msgCount = args.length > 2 ? Integer.parseInt(args[2]) : 100;
+
+ new Subscriber(destination, msgCount).start();
+ }
+
+ public void onMessage(Message message)
+ {
+ try
+ {
+ _count.countDown();
+ System.out.println("Received msg:" + ((TextMessage) message).getText());
+ }
+ catch (JMSException e)
+ {
+ e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
+ }
+ }
+}
diff --git a/Final/java/client/example/src/main/java/org/apache/qpid/example/shared/ConnectionException.java b/Final/java/client/example/src/main/java/org/apache/qpid/example/shared/ConnectionException.java
new file mode 100644
index 0000000000..6eb847ea9d
--- /dev/null
+++ b/Final/java/client/example/src/main/java/org/apache/qpid/example/shared/ConnectionException.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.example.shared;
+
+public class ConnectionException extends Exception
+{
+
+ private int _errorCode;
+
+ public ConnectionException(String message)
+ {
+ super(message);
+ }
+
+ public ConnectionException(String msg, Throwable t)
+ {
+ super(msg, t);
+ }
+
+ public ConnectionException(int errorCode, String msg, Throwable t)
+ {
+ super(msg + " [error code " + errorCode + ']', t);
+ _errorCode = errorCode;
+ }
+
+ public ConnectionException(int errorCode, String msg)
+ {
+ super(msg + " [error code " + errorCode + ']');
+ _errorCode = errorCode;
+ }
+
+ public int getErrorCode()
+ {
+ return _errorCode;
+ }
+}
diff --git a/Final/java/client/example/src/main/java/org/apache/qpid/example/shared/ContextException.java b/Final/java/client/example/src/main/java/org/apache/qpid/example/shared/ContextException.java
new file mode 100644
index 0000000000..bf805ab817
--- /dev/null
+++ b/Final/java/client/example/src/main/java/org/apache/qpid/example/shared/ContextException.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.example.shared;
+
+public class ContextException extends Exception
+{
+
+ private int _errorCode;
+
+ public ContextException(String message)
+ {
+ super(message);
+ }
+
+ public ContextException(String msg, Throwable t)
+ {
+ super(msg, t);
+ }
+
+ public ContextException(int errorCode, String msg, Throwable t)
+ {
+ super(msg + " [error code " + errorCode + ']', t);
+ _errorCode = errorCode;
+ }
+
+ public ContextException(int errorCode, String msg)
+ {
+ super(msg + " [error code " + errorCode + ']');
+ _errorCode = errorCode;
+ }
+
+ public int getErrorCode()
+ {
+ return _errorCode;
+ }
+}
diff --git a/Final/java/client/example/src/main/java/org/apache/qpid/example/shared/FileUtils.java b/Final/java/client/example/src/main/java/org/apache/qpid/example/shared/FileUtils.java
new file mode 100644
index 0000000000..54446cb6a7
--- /dev/null
+++ b/Final/java/client/example/src/main/java/org/apache/qpid/example/shared/FileUtils.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.example.shared;
+
+import java.io.*;
+
+/**
+ * Class that provides file related utility methods for utility use
+ */
+public class FileUtils {
+
+
+ //Reads file content into String
+ public static String getFileContent(String filePath) throws IOException
+ {
+
+ BufferedReader reader = null;
+ String tempData = "";
+ String eol = "\n\r";
+
+ try
+ {
+ String line;
+ reader = new BufferedReader(new FileReader(filePath));
+ while ((line = reader.readLine()) != null)
+ {
+ if (!tempData.equals(""))
+ {
+ tempData = tempData + eol + line;
+ }
+ else
+ {
+ tempData = line;
+ }
+ }
+ }
+ finally
+ {
+ if (reader != null)
+ {
+ reader.close();
+ }
+ }
+ return tempData;
+ }
+
+ /*
+ * Reads xml from a file and returns it as an array of chars
+ */
+ public static char[] getFileAsCharArray(String filePath) throws IOException
+ {
+ BufferedReader reader = null;
+ char[] tempChars = null;
+ String tempData = "";
+
+ try
+ {
+ String line;
+ reader = new BufferedReader(new FileReader(filePath));
+ while ((line = reader.readLine()) != null)
+ {
+ tempData = tempData + line;
+ }
+ tempChars = tempData.toCharArray();
+ }
+ finally
+ {
+ if (reader != null)
+ {
+ reader.close();
+ }
+ }
+ return tempChars;
+ }
+
+ /*
+ * Write String content to filename provided
+ */
+ public static void writeStringToFile(String content, String path) throws IOException
+ {
+
+ BufferedWriter writer = new BufferedWriter(new FileWriter(new File(path)));
+ writer.write(content);
+ writer.flush();
+ writer.close();
+ }
+
+ /*
+ * Allows moving of files to a new dir and preserves the last bit of the name only
+ */
+ public static void moveFileToNewDir(String path, String newDir) throws IOException
+ {
+ //get file name from current path
+ //while more files in dir publish them
+ File pathFile = new File(path);
+ if (pathFile.isDirectory())
+ {
+ File[] files = pathFile.listFiles();
+ for (File file : files)
+ {
+ moveFileToNewDir(file,newDir);
+ }
+ }
+ }
+
+ /*
+ * Allows moving of a file to a new dir and preserves the last bit of the name only
+ */
+ public static void moveFileToNewDir(File fileToMove, String newDir) throws IOException
+ {
+ moveFile(fileToMove,getArchiveFileName(fileToMove,newDir));
+ }
+
+ /*
+ * Moves file from a given path to a new path with String params
+ */
+ public static void moveFile(String fromPath, String dest) throws IOException
+ {
+ moveFile(new File(fromPath),new File(dest));
+ }
+
+ /*
+ * Moves file from a given path to a new path with mixed params
+ */
+ public static void moveFile(File fileToMove, String dest) throws IOException
+ {
+ moveFile(fileToMove,new File(dest));
+ }
+
+ /*
+ * Moves file from a given path to a new path with File params
+ */
+ public static void moveFile(File fileToMove, File dest) throws IOException
+ {
+ fileToMove.renameTo(dest);
+ }
+
+ /*
+ * Deletes a given file
+ */
+ public static void deleteFile(String filePath) throws IOException
+ {
+ new File(filePath).delete();
+ }
+
+ private static String getArchiveFileName(File fileToMove, String archiveDir)
+ {
+ //get file name from current path
+ String fileName = fileToMove.getName();
+ return archiveDir + File.separator + fileName;
+ }
+}
diff --git a/Final/java/client/example/src/main/java/org/apache/qpid/example/shared/InitialContextHelper.java b/Final/java/client/example/src/main/java/org/apache/qpid/example/shared/InitialContextHelper.java
new file mode 100644
index 0000000000..98a2c0d497
--- /dev/null
+++ b/Final/java/client/example/src/main/java/org/apache/qpid/example/shared/InitialContextHelper.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.example.shared;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Properties;
+
+import javax.naming.InitialContext;
+import javax.naming.NamingException;
+
+import org.apache.log4j.Logger;
+
+/**
+ * Class that provides helper methods for JNDI
+ */
+public class InitialContextHelper
+{
+
+ public static final String _defaultPropertiesName = "example.properties";
+ protected static Properties _fileProperties;
+ protected static InitialContext _initialContext;
+ protected static final Logger _log = Logger.getLogger(InitialContextHelper.class);
+
+ public InitialContextHelper(String propertiesName) throws ContextException
+ {
+ try
+ {
+ if ((propertiesName == null) || (propertiesName.length() == 0))
+ {
+ propertiesName = _defaultPropertiesName;
+ }
+
+ _fileProperties = new Properties();
+ ClassLoader cl = this.getClass().getClassLoader();
+
+ // NB: Need to change path to reflect package if moving classes around !
+ InputStream is = cl.getResourceAsStream("org/apache/qpid/example/shared/" + propertiesName);
+ _fileProperties.load(is);
+ _initialContext = new InitialContext(_fileProperties);
+ }
+ catch (IOException e)
+ {
+ throw new ContextException(e.toString(), e);
+ }
+ catch (NamingException n)
+ {
+ throw new ContextException(n.toString(), n);
+ }
+ }
+
+ public Properties getFileProperties()
+ {
+ return _fileProperties;
+ }
+
+ public InitialContext getInitialContext()
+ {
+ return _initialContext;
+ }
+
+}
diff --git a/Final/java/client/example/src/main/java/org/apache/qpid/example/shared/Statics.java b/Final/java/client/example/src/main/java/org/apache/qpid/example/shared/Statics.java
new file mode 100644
index 0000000000..c056f8a7da
--- /dev/null
+++ b/Final/java/client/example/src/main/java/org/apache/qpid/example/shared/Statics.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.example.shared;
+
+/**
+ * Constants used by AMS Publisher/Subscriber classes
+ */
+public class Statics {
+
+ public static final String TOPIC_NAME = "EXAMPLE_TOPIC";
+
+ public static final String QUEUE_NAME = "EXAMPLE_QUEUE";
+
+ public static final String MONITOR_QUEUE_SUFFIX = "_MONITOR";
+
+ public static final String HOST_PROPERTY = "host";
+
+ public static final String PORT_PROPERTY = "port";
+
+ public static final String USER_PROPERTY = "user";
+
+ public static final String PWD_PROPERTY = "pwd";
+
+ public static final String TOPIC_PROPERTY = "topic";
+
+ public static final String QUEUE_PROPERTY = "queue";
+
+ public static final String VIRTUAL_PATH_PROPERTY = "virtualpath";
+
+ public static final String ARCHIVE_PATH = "archivepath";
+
+ public static final String CLIENT_PROPERTY = "client";
+
+ public static final String FILENAME_PROPERTY = "filename";
+
+ public static final String DEFAULT_USER = "guest";
+
+ public static final String DEFAULT_PWD = "guest";
+
+
+}
diff --git a/Final/java/client/example/src/main/java/org/apache/qpid/example/shared/example.properties b/Final/java/client/example/src/main/java/org/apache/qpid/example/shared/example.properties
new file mode 100644
index 0000000000..a60e3964ad
--- /dev/null
+++ b/Final/java/client/example/src/main/java/org/apache/qpid/example/shared/example.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.
+
+
+java.naming.factory.initial = org.apache.qpid.jndi.PropertiesFileInitialContextFactory
+
+# use the following property to configure the default connector
+#java.naming.provider.url - ignored.
+
+# register some connection factories
+# connectionfactory.[jndiname] = [ConnectionURL]
+connectionfactory.local = amqp://guest:guest@clientid/test?brokerlist='tcp://localhost:5672'
+
+# register some queues in JNDI using the form
+# queue.[jndiName] = [physicalName]
+queue.MyQueue = example.MyQueue
+
+# register some topics in JNDI using the form
+# topic.[jndiName] = [physicalName]
+topic.ibmStocks = stocks.nyse.ibm
+
+# Register an AMQP destination in JNDI
+# NOTE: Qpid currently only supports direct,topics and headers
+# destination.[jniName] = [BindingURL]
+destination.direct = direct://amq.direct//directQueue
diff --git a/Final/java/client/example/src/main/java/org/apache/qpid/example/subscriber/MonitoredSubscriber.java b/Final/java/client/example/src/main/java/org/apache/qpid/example/subscriber/MonitoredSubscriber.java
new file mode 100644
index 0000000000..1d2e5e0e66
--- /dev/null
+++ b/Final/java/client/example/src/main/java/org/apache/qpid/example/subscriber/MonitoredSubscriber.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.example.subscriber;
+
+import org.apache.log4j.Logger;
+import org.apache.qpid.example.shared.Statics;
+
+import javax.jms.*;
+
+/**
+ * Subclass of Subscriber which consumes a heartbeat message
+ */
+
+public class MonitoredSubscriber extends Subscriber
+{
+ protected String _monitorDestinationName;
+
+ private static final Logger _logger = Logger.getLogger(MonitoredSubscriber.class);
+
+ private static MessageConsumer _monitorConsumer;
+
+ public MonitoredSubscriber()
+ {
+ super();
+ //lookup queue name and append suffix
+ _monitorDestinationName = _destination.toString() + Statics.MONITOR_QUEUE_SUFFIX;
+ }
+
+ /**
+ * MessageListener implementation for this subscriber
+ */
+ public static class MonitorMessageListener implements MessageListener
+ {
+ private String _name;
+
+ public MonitorMessageListener(String name)
+ {
+ _name = name;
+
+ }
+
+ /**
+ * Listens for heartbeat messages and acknowledges them
+ * @param message
+ */
+ public void onMessage(javax.jms.Message message)
+ {
+ _logger.info(_name + " monitor got message '" + message + "'");
+
+ try
+ {
+ _logger.debug("Monitor acknowledging recieved message");
+
+ //Now acknowledge the message to clear it from our queue
+ message.acknowledge();
+ }
+ catch(JMSException j)
+ {
+ _logger.error("Monitor caught JMSException trying to acknowledge message receipt");
+ j.printStackTrace();
+ }
+ catch(Exception e)
+ {
+ _logger.error("Monitor caught unexpected exception trying to handle message");
+ e.printStackTrace();
+ }
+ }
+ }
+
+ /**
+ * Subscribes to Queue and attaches additional monitor listener
+ */
+ public void subscribeAndMonitor()
+ {
+ try
+ {
+ _connection = _connectionFactory.createConnection();
+
+ //create a transactional session
+ Session session = _connection.createSession(true, Session.AUTO_ACKNOWLEDGE);
+
+ //Queue is non-exclusive and not deleted when last consumer detaches
+ Destination destination = session.createQueue(_monitorDestinationName);
+
+ //Create a consumer with a destination of our queue which will use defaults for prefetch etc
+ _monitorConsumer = session.createConsumer(destination);
+
+ //give the monitor message listener a name of it's own
+ _monitorConsumer.setMessageListener(new MonitoredSubscriber.MonitorMessageListener
+ ("MonitorListener " + System.currentTimeMillis()));
+
+ MonitoredSubscriber._logger.info("Starting monitored subscription ...");
+
+ MonitoredSubscriber._connection.start();
+
+ //and now start ordinary consumption too
+ subscribe();
+ }
+ catch (Throwable t)
+ {
+ _logger.error("Fatal error: " + t);
+ t.printStackTrace();
+ }
+ }
+
+ /**
+ * Stop consuming
+ */
+ public void stopMonitor()
+ {
+ try
+ {
+ _monitorConsumer.close();
+ _monitorConsumer = null;
+ stop();
+ }
+ catch(JMSException j)
+ {
+ _logger.error("JMSException trying to Subscriber.stop: " + j.getStackTrace());
+ }
+ }
+
+}
diff --git a/Final/java/client/example/src/main/java/org/apache/qpid/example/subscriber/MonitoredSubscriptionWrapper.java b/Final/java/client/example/src/main/java/org/apache/qpid/example/subscriber/MonitoredSubscriptionWrapper.java
new file mode 100644
index 0000000000..d2f27da052
--- /dev/null
+++ b/Final/java/client/example/src/main/java/org/apache/qpid/example/subscriber/MonitoredSubscriptionWrapper.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.example.subscriber;
+
+import org.apache.log4j.BasicConfigurator;
+
+/**
+ * Allows you to simply start a monitored subscriber
+ */
+public class MonitoredSubscriptionWrapper {
+
+ private static MonitoredSubscriber _subscriber;
+
+ /**
+ * Create a monitored subscriber and start it
+ * @param args - no params required
+ */
+ public static void main(String args[])
+ {
+ //switch on logging
+ BasicConfigurator.configure();
+
+ _subscriber = new MonitoredSubscriber();
+
+ _subscriber.subscribe();
+ }
+
+ /**
+ * Stop subscribing now ...
+ */
+ public static void stop()
+ {
+ _subscriber.stop();
+ }
+}
diff --git a/Final/java/client/example/src/main/java/org/apache/qpid/example/subscriber/Subscriber.java b/Final/java/client/example/src/main/java/org/apache/qpid/example/subscriber/Subscriber.java
new file mode 100644
index 0000000000..d443dca828
--- /dev/null
+++ b/Final/java/client/example/src/main/java/org/apache/qpid/example/subscriber/Subscriber.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.example.subscriber;
+
+import org.apache.log4j.Logger;
+import org.apache.qpid.client.AMQConnectionFactory;
+
+import javax.jms.*;
+import javax.jms.Connection;
+import javax.jms.MessageConsumer;
+import javax.jms.Session;
+import javax.naming.InitialContext;
+
+import org.apache.qpid.example.shared.InitialContextHelper;
+
+/**
+ * Subscriber which consumes messages from a queue
+ */
+
+public class Subscriber
+{
+ private static final Logger _log = Logger.getLogger(Subscriber.class);
+
+ protected static Connection _connection;
+
+ protected static MessageConsumer _consumer;
+
+ protected static InitialContextHelper _contextHelper;
+
+ protected static AMQConnectionFactory _connectionFactory;
+
+ protected Destination _destination;
+
+ public Subscriber()
+ {
+ try
+ {
+ //get an initial context from default properties
+ _contextHelper = new InitialContextHelper(null);
+ InitialContext ctx = _contextHelper.getInitialContext();
+
+ //then create a connection using the AMQConnectionFactory
+ _connectionFactory = (AMQConnectionFactory) ctx.lookup("local");
+
+ //lookup queue from context
+ _destination = (Destination) ctx.lookup("MyQueue");
+
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ _log.error(e);
+ }
+ }
+
+ /**
+ * Listener class that handles messages
+ */
+ public static class ExampleMessageListener implements MessageListener
+ {
+ private String _name;
+
+ public ExampleMessageListener(String name)
+ {
+ _name = name;
+ }
+
+ /**
+ * Listens for message callbacks, handles and then acknowledges them
+ * @param message - the message received
+ */
+ public void onMessage(javax.jms.Message message)
+ {
+ _log.info(_name + " got message '" + message + "'");
+
+ try
+ {
+ //NB: Handle your message appropriately for your application here
+ //do some stuff
+
+ _log.debug("Acknowledging recieved message");
+
+ //Now acknowledge the message to clear it from our queue
+ message.acknowledge();
+ }
+ catch(JMSException j)
+ {
+ _log.error("JMSException trying to acknowledge message receipt");
+ j.printStackTrace();
+ }
+ catch(Exception e)
+ {
+ _log.error("Unexpected exception trying to handle message");
+ e.printStackTrace();
+ }
+ }
+ }
+
+ /**
+ * Subscribes to example Queue and attaches listener
+ */
+ public void subscribe()
+ {
+ _log.info("Starting subscription ...");
+
+ try
+ {
+ _connection = _connectionFactory.createConnection();
+
+ //Non transactional session using client acknowledgement
+ Session session = _connection.createSession(false, Session.CLIENT_ACKNOWLEDGE);
+
+ //Create a consumer with a destination of our queue which will use defaults for prefetch etc
+ _consumer = session.createConsumer(_destination);
+
+ //give the message listener a name of it's own
+ _consumer.setMessageListener(new ExampleMessageListener("MessageListener " + System.currentTimeMillis()));
+
+ _connection.start();
+ }
+ catch (Throwable t)
+ {
+ _log.error("Fatal error: " + t);
+ t.printStackTrace();
+ }
+
+ _log.info("Waiting for messages ...");
+
+ //wait for messages and sleep to survive failover
+ try
+ {
+ while(true)
+ {
+ Thread.sleep(Long.MAX_VALUE);
+ }
+ }
+ catch (Exception e)
+ {
+ _log.warn("Exception while Subscriber sleeping",e);
+ }
+ }
+
+ /**
+ * Stop consuming and close connection
+ */
+ public void stop()
+ {
+ try
+ {
+ _consumer.close();
+ _consumer = null;
+ _connection.stop();
+ _connection.close();
+ }
+ catch(JMSException j)
+ {
+ _log.error("JMSException trying to Subscriber.stop: " + j.getStackTrace());
+ }
+ }
+
+}
+
+
+
+
diff --git a/Final/java/client/example/src/main/java/org/apache/qpid/example/subscriber/SubscriptionWrapper.java b/Final/java/client/example/src/main/java/org/apache/qpid/example/subscriber/SubscriptionWrapper.java
new file mode 100644
index 0000000000..32a0ef685c
--- /dev/null
+++ b/Final/java/client/example/src/main/java/org/apache/qpid/example/subscriber/SubscriptionWrapper.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.example.subscriber;
+
+import org.apache.log4j.BasicConfigurator;
+
+/**
+ * Allows you to simply start a subscriber
+ */
+public class SubscriptionWrapper {
+
+ private static Subscriber _subscriber;
+
+ /**
+ * Create a subscriber and start it
+ * @param args
+ */
+ public static void main(String args[])
+ {
+ //switch on logging
+ BasicConfigurator.configure();
+
+ _subscriber = new Subscriber();
+
+ _subscriber.subscribe();
+ }
+
+ /**
+ * Stop subscribing now ...
+ */
+ public static void stop()
+ {
+ _subscriber.stop();
+ }
+}
diff --git a/Final/java/client/pom.xml b/Final/java/client/pom.xml
new file mode 100644
index 0000000000..0f0757e9a3
--- /dev/null
+++ b/Final/java/client/pom.xml
@@ -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.
+-->
+<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-M2</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-M2</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>uk.co.thebadgerset</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>
+ <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>
+ <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>
+
+ </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/Final/java/client/src/main/java/client.log4j b/Final/java/client/src/main/java/client.log4j
new file mode 100644
index 0000000000..525433e9a9
--- /dev/null
+++ b/Final/java/client/src/main/java/client.log4j
@@ -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.
+#
+log4j.rootLogger=${root.logging.level}
+
+
+log4j.logger.org.apache.qpid=${amqj.logging.level}, console
+log4j.additivity.org.apache.qpid=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
diff --git a/Final/java/client/src/main/java/org/apache/qpid/client/AMQAuthenticationException.java b/Final/java/client/src/main/java/org/apache/qpid/client/AMQAuthenticationException.java
new file mode 100644
index 0000000000..b6fbb6c6bf
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/AMQAuthenticationException.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.AMQException;
+import org.apache.qpid.protocol.AMQConstant;
+
+/**
+ * AMQAuthenticationException represents all failures to authenticate access to a broker.
+ *
+ * <p/><table id="crc"><caption>CRC Card</caption>
+ * <tr><th> Responsibilities <th> Collaborations
+ * <tr><td> Represent failure to authenticate the client.
+ * </table>
+ *
+ * @todo Will this alwyas have the same status code, NOT_ALLOWED 530? Might set this up to always use that code.
+ */
+public class AMQAuthenticationException extends AMQException
+{
+ public AMQAuthenticationException(AMQConstant error, String msg)
+ {
+ super(error, msg);
+ }
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/client/AMQBrokerDetails.java b/Final/java/client/src/main/java/org/apache/qpid/client/AMQBrokerDetails.java
new file mode 100644
index 0000000000..c04380ba8c
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/AMQBrokerDetails.java
@@ -0,0 +1,353 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.client;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.HashMap;
+
+import org.apache.qpid.jms.BrokerDetails;
+import org.apache.qpid.url.URLHelper;
+import org.apache.qpid.url.URLSyntaxException;
+
+public class AMQBrokerDetails implements BrokerDetails
+{
+ private String _host;
+ private int _port;
+ private String _transport;
+
+ private HashMap<String, String> _options;
+
+ private SSLConfiguration _sslConfiguration;
+
+ public AMQBrokerDetails()
+ {
+ _options = new HashMap<String, String>();
+ }
+
+ public AMQBrokerDetails(String url) throws URLSyntaxException
+ {
+ this();
+ // URL should be of format tcp://host:port?option='value',option='value'
+ try
+ {
+ URI connection = new URI(url);
+
+ String transport = connection.getScheme();
+
+ // Handles some defaults to minimise changes to existing broker URLS e.g. localhost
+ if (transport != null)
+ {
+ //todo this list of valid transports should be enumerated somewhere
+ if ((!(transport.equalsIgnoreCase("vm") ||
+ transport.equalsIgnoreCase("tcp"))))
+ {
+ if (transport.equalsIgnoreCase("localhost"))
+ {
+ connection = new URI(DEFAULT_TRANSPORT + "://" + url);
+ transport = connection.getScheme();
+ }
+ else
+ {
+ if (url.charAt(transport.length()) == ':' && url.charAt(transport.length() + 1) != '/')
+ {
+ //Then most likely we have a host:port value
+ connection = new URI(DEFAULT_TRANSPORT + "://" + url);
+ transport = connection.getScheme();
+ }
+ else
+ {
+ throw URLHelper.parseError(0, transport.length(), "Unknown transport", url);
+ }
+ }
+ }
+ }
+ else
+ {
+ //Default the transport
+ connection = new URI(DEFAULT_TRANSPORT + "://" + url);
+ transport = connection.getScheme();
+ }
+
+ if (transport == null)
+ {
+ throw URLHelper.parseError(-1, "Unknown transport:'" + transport + "'" +
+ " In broker URL:'" + url + "' Format: " + URL_FORMAT_EXAMPLE, "");
+ }
+
+ setTransport(transport);
+
+ String host = connection.getHost();
+
+ // Fix for Java 1.5
+ if (host == null)
+ {
+ host = "";
+ }
+
+ setHost(host);
+
+ int port = connection.getPort();
+
+ if (port == -1)
+ {
+ // Fix for when there is port data but it is not automatically parseable by getPort().
+ String auth = connection.getAuthority();
+
+ if (auth != null && auth.contains(":"))
+ {
+ int start = auth.indexOf(":") + 1;
+ int end = start;
+ boolean looking = true;
+ boolean found = false;
+ //Walk the authority looking for a port value.
+ while (looking)
+ {
+ try
+ {
+ end++;
+ Integer.parseInt(auth.substring(start, end));
+
+ if (end >= auth.length())
+ {
+ looking = false;
+ found = true;
+ }
+ }
+ catch (NumberFormatException nfe)
+ {
+ looking = false;
+ }
+
+ }
+ if (found)
+ {
+ setPort(Integer.parseInt(auth.substring(start, end)));
+ }
+ else
+ {
+ throw URLHelper.parseError(connection.toString().indexOf(connection.getAuthority()) + end - 1,
+ "Illegal character in port number", connection.toString());
+ }
+
+ }
+ else
+ {
+ setPort(DEFAULT_PORT);
+ }
+ }
+ else
+ {
+ setPort(port);
+ }
+
+ String queryString = connection.getQuery();
+
+ URLHelper.parseOptions(_options, queryString);
+
+ //Fragment is #string (not used)
+ }
+ catch (URISyntaxException uris)
+ {
+ if (uris instanceof URLSyntaxException)
+ {
+ throw(URLSyntaxException) uris;
+ }
+
+ throw URLHelper.parseError(uris.getIndex(), uris.getReason(), uris.getInput());
+ }
+ }
+
+ public AMQBrokerDetails(String host, int port, SSLConfiguration sslConfiguration)
+ {
+ _host = host;
+ _port = port;
+ _sslConfiguration = sslConfiguration;
+ }
+
+ 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 getTransport()
+ {
+ return _transport;
+ }
+
+ public void setTransport(String _transport)
+ {
+ this._transport = _transport;
+ }
+
+
+ public String getOption(String key)
+ {
+ return _options.get(key);
+ }
+
+ public void setOption(String key, String value)
+ {
+ _options.put(key, value);
+ }
+
+ public long getTimeout()
+ {
+ if (_options.containsKey(OPTIONS_CONNECT_TIMEOUT))
+ {
+ try
+ {
+ return Long.parseLong(_options.get(OPTIONS_CONNECT_TIMEOUT));
+ }
+ catch (NumberFormatException nfe)
+ {
+ //Do nothing as we will use the default below.
+ }
+ }
+
+ return BrokerDetails.DEFAULT_CONNECT_TIMEOUT;
+ }
+
+ public void setTimeout(long timeout)
+ {
+ setOption(OPTIONS_CONNECT_TIMEOUT, Long.toString(timeout));
+ }
+
+ public SSLConfiguration getSSLConfiguration()
+ {
+ return _sslConfiguration;
+ }
+
+ public void setSSLConfiguration(SSLConfiguration sslConfig)
+ {
+ _sslConfiguration = sslConfig;
+ }
+
+ public String toString()
+ {
+ StringBuffer sb = new StringBuffer();
+
+ sb.append(_transport);
+ sb.append("://");
+
+ if (!(_transport.equalsIgnoreCase("vm")))
+ {
+ sb.append(_host);
+ }
+
+ sb.append(':');
+ sb.append(_port);
+
+ sb.append(printOptionsURL());
+
+ return sb.toString();
+ }
+
+ public boolean equals(Object o)
+ {
+ if (!(o instanceof BrokerDetails))
+ {
+ return false;
+ }
+
+ BrokerDetails bd = (BrokerDetails) o;
+
+ return _host.equalsIgnoreCase(bd.getHost()) &&
+ (_port == bd.getPort()) &&
+ _transport.equalsIgnoreCase(bd.getTransport()) &&
+ compareSSLConfigurations(bd.getSSLConfiguration());
+ //todo do we need to compare all the options as well?
+ }
+
+ private String printOptionsURL()
+ {
+ StringBuffer optionsURL = new StringBuffer();
+
+ optionsURL.append('?');
+
+ if (!(_options.isEmpty()))
+ {
+
+ for (String key : _options.keySet())
+ {
+ optionsURL.append(key);
+
+ optionsURL.append("='");
+
+ optionsURL.append(_options.get(key));
+
+ optionsURL.append("'");
+
+ optionsURL.append(URLHelper.DEFAULT_OPTION_SEPERATOR);
+ }
+ }
+
+ //removeKey the extra DEFAULT_OPTION_SEPERATOR or the '?' if there are no options
+ optionsURL.deleteCharAt(optionsURL.length() - 1);
+
+ return optionsURL.toString();
+ }
+
+ // Do we need to do a more in-depth comparison?
+ private boolean compareSSLConfigurations(SSLConfiguration other)
+ {
+ boolean retval = false;
+ if (_sslConfiguration == null &&
+ other == null)
+ {
+ retval = true;
+ }
+ else if (_sslConfiguration != null &&
+ other != null)
+ {
+ retval = true;
+ }
+
+ return retval;
+ }
+
+ public static String checkTransport(String broker)
+ {
+ if ((!broker.contains("://")))
+ {
+ return "tcp://" + broker;
+ }
+ else
+ {
+ return broker;
+ }
+ }
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/client/AMQConnection.java b/Final/java/client/src/main/java/org/apache/qpid/client/AMQConnection.java
new file mode 100644
index 0000000000..9abc94b3df
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/AMQConnection.java
@@ -0,0 +1,1289 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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.AMQConnectionFailureException;
+import org.apache.qpid.AMQException;
+import org.apache.qpid.AMQUndeliveredException;
+import org.apache.qpid.AMQUnresolvedAddressException;
+import org.apache.qpid.client.failover.FailoverException;
+import org.apache.qpid.client.failover.FailoverProtectedOperation;
+import org.apache.qpid.client.failover.FailoverRetrySupport;
+import org.apache.qpid.client.protocol.AMQProtocolHandler;
+import org.apache.qpid.client.state.AMQState;
+import org.apache.qpid.client.state.AMQStateManager;
+import org.apache.qpid.client.transport.TransportConnection;
+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.TxSelectBody;
+import org.apache.qpid.framing.TxSelectOkBody;
+import org.apache.qpid.jms.BrokerDetails;
+import org.apache.qpid.jms.ChannelLimitReachedException;
+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.url.URLSyntaxException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.jms.ConnectionConsumer;
+import javax.jms.ConnectionMetaData;
+import javax.jms.Destination;
+import javax.jms.ExceptionListener;
+import javax.jms.IllegalStateException;
+import javax.jms.JMSException;
+import javax.jms.Queue;
+import javax.jms.QueueConnection;
+import javax.jms.QueueSession;
+import javax.jms.ServerSessionPool;
+import javax.jms.Topic;
+import javax.jms.TopicConnection;
+import javax.jms.TopicSession;
+import javax.naming.NamingException;
+import javax.naming.Reference;
+import javax.naming.Referenceable;
+import javax.naming.StringRefAddr;
+import java.io.IOException;
+import java.net.ConnectException;
+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;
+
+public class AMQConnection extends Closeable implements Connection, QueueConnection, TopicConnection, Referenceable
+{
+ private static final Logger _logger = LoggerFactory.getLogger(AMQConnection.class);
+
+ private 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
+ * held by any child objects of this connection such as the session, producers and consumers.
+ */
+ private final Object _failoverMutex = new Object();
+
+ private final Object _sessionCreationLock = new Object();
+
+ /**
+ * A channel is roughly analogous to a session. The server can negotiate the maximum number of channels per session
+ * and we must prevent the client from opening too many. Zero means unlimited.
+ */
+ private long _maximumChannelCount;
+
+ /** The maximum size of frame supported by the server */
+ private long _maximumFrameSize;
+
+ /**
+ * The protocol handler dispatches protocol events for this connection. For example, when the connection is dropped
+ * the handler deals with this. It also deals with the initial dispatch of any protocol frames to their appropriate
+ * handler.
+ */
+ private AMQProtocolHandler _protocolHandler;
+
+ /** Maps from session id (Integer) to AMQSession instance */
+ private final Map<Integer, AMQSession> _sessions = new LinkedHashMap<Integer, AMQSession>();
+
+ private String _clientName;
+
+ /** The user name to use for authentication */
+ private String _username;
+
+ /** The password to use for authentication */
+ private String _password;
+
+ /** The virtual path to connect to on the AMQ server */
+ private String _virtualHost;
+
+ private ExceptionListener _exceptionListener;
+
+ private ConnectionListener _connectionListener;
+
+ private ConnectionURL _connectionURL;
+
+ /**
+ * Whether this connection is started, i.e. whether messages are flowing to consumers. It has no meaning for message
+ * publication.
+ */
+ private boolean _started;
+
+ /** Policy dictating how to failover */
+ private FailoverPolicy _failoverPolicy;
+
+ /*
+ * _Connected should be refactored with a suitable wait object.
+ */
+ private boolean _connected;
+
+ /*
+ * The last error code that occured on the connection. Used to return the correct exception to the client
+ */
+ private AMQException _lastAMQException = null;
+
+ /*
+ * The connection meta data
+ */
+ private QpidConnectionMetaData _connectionMetaData;
+
+ /** Configuration info for SSL */
+ private SSLConfiguration _sslConfiguration;
+
+ private AMQShortString _defaultTopicExchangeName = ExchangeDefaults.TOPIC_EXCHANGE_NAME;
+ private AMQShortString _defaultQueueExchangeName = ExchangeDefaults.DIRECT_EXCHANGE_NAME;
+ private AMQShortString _temporaryTopicExchangeName = ExchangeDefaults.TOPIC_EXCHANGE_NAME;
+ private AMQShortString _temporaryQueueExchangeName = ExchangeDefaults.DIRECT_EXCHANGE_NAME;
+
+ /** 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;
+
+ /**
+ * @param broker brokerdetails
+ * @param username username
+ * @param password password
+ * @param clientName clientid
+ * @param virtualHost virtualhost
+ *
+ * @throws AMQException
+ * @throws URLSyntaxException
+ */
+ public AMQConnection(String broker, String username, String password, String clientName, String virtualHost)
+ throws AMQException, URLSyntaxException
+ {
+ this(new AMQConnectionURL(
+ ConnectionURL.AMQ_PROTOCOL + "://" + username + ":" + password + "@"
+ + ((clientName == null) ? "" : clientName) + "/" + virtualHost + "?brokerlist='"
+ + AMQBrokerDetails.checkTransport(broker) + "'"), null);
+ }
+
+ /**
+ * @param broker brokerdetails
+ * @param username username
+ * @param password password
+ * @param clientName clientid
+ * @param virtualHost virtualhost
+ *
+ * @throws AMQException
+ * @throws URLSyntaxException
+ */
+ public AMQConnection(String broker, String username, String password, String clientName, String virtualHost,
+ SSLConfiguration sslConfig) throws AMQException, URLSyntaxException
+ {
+ this(new AMQConnectionURL(
+ ConnectionURL.AMQ_PROTOCOL + "://" + username + ":" + password + "@"
+ + ((clientName == null) ? "" : clientName) + "/" + virtualHost + "?brokerlist='"
+ + AMQBrokerDetails.checkTransport(broker) + "'"), sslConfig);
+ }
+
+ public AMQConnection(String host, int port, String username, String password, String clientName, String virtualHost)
+ throws AMQException, URLSyntaxException
+ {
+ this(host, port, false, username, password, clientName, virtualHost, null);
+ }
+
+ public AMQConnection(String host, int port, String username, String password, String clientName, String virtualHost,
+ SSLConfiguration sslConfig) throws AMQException, URLSyntaxException
+ {
+ this(host, port, false, username, password, clientName, virtualHost, sslConfig);
+ }
+
+ public AMQConnection(String host, int port, boolean useSSL, String username, String password, String clientName,
+ String virtualHost, SSLConfiguration sslConfig) throws AMQException, URLSyntaxException
+ {
+ this(new AMQConnectionURL(
+ useSSL
+ ? (ConnectionURL.AMQ_PROTOCOL + "://" + username + ":" + password + "@"
+ + ((clientName == null) ? "" : clientName) + virtualHost + "?brokerlist='tcp://" + host + ":" + port
+ + "'" + "," + ConnectionURL.OPTIONS_SSL + "='true'")
+ : (ConnectionURL.AMQ_PROTOCOL + "://" + username + ":" + password + "@"
+ + ((clientName == null) ? "" : clientName) + virtualHost + "?brokerlist='tcp://" + host + ":" + port
+ + "'" + "," + ConnectionURL.OPTIONS_SSL + "='false'")), sslConfig);
+ }
+
+ public AMQConnection(String connection) throws AMQException, URLSyntaxException
+ {
+ this(new AMQConnectionURL(connection), null);
+ }
+
+ public AMQConnection(String connection, SSLConfiguration sslConfig) throws AMQException, URLSyntaxException
+ {
+ this(new AMQConnectionURL(connection), sslConfig);
+ }
+
+ public AMQConnection(ConnectionURL connectionURL, SSLConfiguration sslConfig) throws AMQException
+ {
+ if (_logger.isInfoEnabled())
+ {
+ _logger.info("Connection:" + connectionURL);
+ }
+
+ _sslConfiguration = sslConfig;
+ if (connectionURL == null)
+ {
+ throw new IllegalArgumentException("Connection must be specified");
+ }
+
+ _connectionURL = connectionURL;
+
+ _clientName = connectionURL.getClientName();
+ _username = connectionURL.getUsername();
+ _password = connectionURL.getPassword();
+ setVirtualHost(connectionURL.getVirtualHost());
+
+ if (connectionURL.getDefaultQueueExchangeName() != null)
+ {
+ _defaultQueueExchangeName = connectionURL.getDefaultQueueExchangeName();
+ }
+
+ if (connectionURL.getDefaultTopicExchangeName() != null)
+ {
+ _defaultTopicExchangeName = connectionURL.getDefaultTopicExchangeName();
+ }
+
+ if (connectionURL.getTemporaryQueueExchangeName() != null)
+ {
+ _temporaryQueueExchangeName = connectionURL.getTemporaryQueueExchangeName();
+ }
+
+ if (connectionURL.getTemporaryTopicExchangeName() != null)
+ {
+ _temporaryTopicExchangeName = connectionURL.getTemporaryTopicExchangeName();
+ }
+
+ _failoverPolicy = new FailoverPolicy(connectionURL);
+
+ _protocolHandler = new AMQProtocolHandler(this);
+
+ // We are not currently connected
+ _connected = false;
+
+ Exception lastException = new Exception();
+ lastException.initCause(new ConnectException());
+
+ while (!_connected && _failoverPolicy.failoverAllowed())
+ {
+ try
+ {
+ makeBrokerConnection(_failoverPolicy.getNextBrokerDetails());
+ lastException = null;
+ _connected = true;
+ }
+ catch (Exception e)
+ {
+ lastException = e;
+
+ //We need to change protocol handler here as an error during the connect will not
+ // cause the StateManager to be replaced. So the state is out of sync on reconnect
+ // This can be seen when a exception occurs during connection. i.e. log4j NoSuchMethod. (using < 1.2.12)
+ _protocolHandler.setStateManager(new AMQStateManager());
+
+ if (_logger.isInfoEnabled())
+ {
+ _logger.info("Unable to connect to broker at " + _failoverPolicy.getCurrentBrokerDetails(),
+ e.getCause());
+ }
+ }
+ }
+
+ if (_logger.isDebugEnabled())
+ {
+ _logger.debug("Are we connected:" + _connected);
+ }
+
+ if (!_connected)
+ {
+ String message = null;
+
+ if (lastException != null)
+ {
+ if (lastException.getCause() != null)
+ {
+ message = lastException.getCause().getMessage();
+ }
+ else
+ {
+ message = lastException.getMessage();
+ }
+ }
+
+ if ((message == null) || message.equals(""))
+ {
+ if (message == null)
+ {
+ message = "Unable to Connect";
+ }
+ else // can only be "" if getMessage() returned it therfore lastException != null
+ {
+ message = "Unable to Connect:" + lastException.getClass();
+ }
+ }
+
+ AMQException e = new AMQConnectionFailureException(message);
+
+ if (lastException != null)
+ {
+ if (lastException instanceof UnresolvedAddressException)
+ {
+ e = new AMQUnresolvedAddressException(message, _failoverPolicy.getCurrentBrokerDetails().toString());
+ }
+
+ e.initCause(lastException);
+ }
+
+ throw e;
+ }
+
+ _connectionMetaData = new QpidConnectionMetaData(this);
+ }
+
+ protected boolean checkException(Throwable thrown)
+ {
+ Throwable cause = thrown.getCause();
+
+ if (cause == null)
+ {
+ cause = thrown;
+ }
+
+ return ((cause instanceof ConnectException) || (cause instanceof UnresolvedAddressException));
+ }
+
+ protected AMQConnection(String username, String password, String clientName, String virtualHost)
+ {
+ _clientName = clientName;
+ _username = username;
+ _password = password;
+ setVirtualHost(virtualHost);
+ }
+
+ private void setVirtualHost(String virtualHost)
+ {
+ if (virtualHost.startsWith("/"))
+ {
+ virtualHost = virtualHost.substring(1);
+ }
+
+ _virtualHost = virtualHost;
+ }
+
+ private void makeBrokerConnection(BrokerDetails brokerDetail) throws IOException, AMQException
+ {
+ try
+ {
+ TransportConnection.getInstance(brokerDetail).connect(_protocolHandler, brokerDetail);
+ // this blocks until the connection has been set up or when an error
+ // has prevented the connection being set up
+ _protocolHandler.attainState(AMQState.CONNECTION_OPEN);
+ _failoverPolicy.attainedConnection();
+
+ // Again this should be changed to a suitable notify
+ _connected = true;
+ }
+ catch (AMQException e)
+ {
+ _lastAMQException = e;
+ throw e;
+ }
+ }
+
+ public boolean attemptReconnection(String host, int port)
+ {
+ BrokerDetails bd = new AMQBrokerDetails(host, port, _sslConfiguration);
+
+ _failoverPolicy.setBroker(bd);
+
+ try
+ {
+ makeBrokerConnection(bd);
+
+ return true;
+ }
+ catch (Exception e)
+ {
+ if (_logger.isInfoEnabled())
+ {
+ _logger.info("Unable to connect to broker at " + bd);
+ }
+
+ attemptReconnection();
+ }
+
+ return false;
+ }
+
+ public boolean attemptReconnection()
+ {
+ while (_failoverPolicy.failoverAllowed())
+ {
+ try
+ {
+ makeBrokerConnection(_failoverPolicy.getNextBrokerDetails());
+
+ return true;
+ }
+ catch (Exception e)
+ {
+ if (!(e instanceof AMQException))
+ {
+ if (_logger.isInfoEnabled())
+ {
+ _logger.info("Unable to connect to broker at " + _failoverPolicy.getCurrentBrokerDetails(), e);
+ }
+ }
+ else
+ {
+ if (_logger.isInfoEnabled())
+ {
+ _logger.info(e.getMessage() + ":Unable to connect to broker at "
+ + _failoverPolicy.getCurrentBrokerDetails());
+ }
+ }
+ }
+ }
+
+ // connection unsuccessful
+ return false;
+ }
+
+ /**
+ * Get the details of the currently active broker
+ *
+ * @return null if no broker is active (i.e. no successful connection has been made, or the BrokerDetail instance
+ * otherwise
+ */
+ public BrokerDetails getActiveBrokerDetails()
+ {
+ return _failoverPolicy.getCurrentBrokerDetails();
+ }
+
+ public boolean failoverAllowed()
+ {
+ if (!_connected)
+ {
+ return false;
+ }
+ else
+ {
+ return _failoverPolicy.failoverAllowed();
+ }
+ }
+
+ public org.apache.qpid.jms.Session createSession(final boolean transacted, final int acknowledgeMode) throws JMSException
+ {
+ return createSession(transacted, acknowledgeMode, AMQSession.DEFAULT_PREFETCH_HIGH_MARK);
+ }
+
+ public org.apache.qpid.jms.Session createSession(final boolean transacted, final int acknowledgeMode, final int prefetch)
+ throws JMSException
+ {
+ return createSession(transacted, acknowledgeMode, prefetch, prefetch);
+ }
+
+ public org.apache.qpid.jms.Session createSession(final boolean transacted, final int acknowledgeMode,
+ final int prefetchHigh, final int prefetchLow) throws JMSException
+ {
+ synchronized(_sessionCreationLock)
+ {
+ checkNotClosed();
+
+ if (channelLimitReached())
+ {
+ throw new ChannelLimitReachedException(_maximumChannelCount);
+ }
+
+ return new FailoverRetrySupport<org.apache.qpid.jms.Session, JMSException>(
+ new FailoverProtectedOperation<org.apache.qpid.jms.Session, JMSException>()
+ {
+ public org.apache.qpid.jms.Session execute() throws JMSException, FailoverException
+ {
+ int channelId = _idFactory.incrementAndGet();
+
+ if (_logger.isDebugEnabled())
+ {
+ _logger.debug("Write channel open frame for channel id " + channelId);
+ }
+
+ // We must create the session and register it before actually sending the frame to the server to
+ // open it, so that there is no window where we could receive data on the channel and not be set
+ // up to handle it appropriately.
+ AMQSession session =
+ new AMQSession(AMQConnection.this, channelId, transacted, acknowledgeMode, prefetchHigh,
+ prefetchLow);
+ // _protocolHandler.addSessionByChannel(channelId, session);
+ registerSession(channelId, session);
+
+ boolean success = false;
+ try
+ {
+ createChannelOverWire(channelId, prefetchHigh, prefetchLow, transacted);
+ success = true;
+ }
+ catch (AMQException e)
+ {
+ JMSException jmse = new JMSException("Error creating session: " + e);
+ jmse.setLinkedException(e);
+ throw jmse;
+ }
+ finally
+ {
+ if (!success)
+ {
+ deregisterSession(channelId);
+ }
+ }
+
+ if (_started)
+ {
+ try
+ {
+ session.start();
+ }
+ catch (AMQException e)
+ {
+ throw new JMSAMQException(e);
+ }
+ }
+
+ return session;
+ }
+ }, this).execute();
+ }
+ }
+
+ private void createChannelOverWire(int channelId, int prefetchHigh, int prefetchLow, boolean transacted)
+ throws AMQException, FailoverException
+ {
+
+ // TODO: Be aware of possible changes to parameter order as versions change.
+
+ _protocolHandler.syncWrite(ChannelOpenBody.createAMQFrame(channelId, _protocolHandler.getProtocolMajorVersion(),
+ _protocolHandler.getProtocolMinorVersion(), null), // outOfBand
+ ChannelOpenOkBody.class);
+
+ // todo send low water mark when protocol allows.
+ // todo Be aware of possible changes to parameter order as versions change.
+ _protocolHandler.syncWrite(BasicQosBody.createAMQFrame(channelId, _protocolHandler.getProtocolMajorVersion(),
+ _protocolHandler.getProtocolMinorVersion(), false, // global
+ prefetchHigh, // prefetchCount
+ 0), // prefetchSize
+ BasicQosOkBody.class);
+
+ if (transacted)
+ {
+ if (_logger.isDebugEnabled())
+ {
+ _logger.debug("Issuing TxSelect for " + channelId);
+ }
+
+ // TODO: Be aware of possible changes to parameter order as versions change.
+ _protocolHandler.syncWrite(TxSelectBody.createAMQFrame(channelId, _protocolHandler.getProtocolMajorVersion(),
+ _protocolHandler.getProtocolMinorVersion()), TxSelectOkBody.class);
+ }
+ }
+
+ private void reopenChannel(int channelId, int prefetchHigh, int prefetchLow, boolean transacted)
+ throws AMQException, FailoverException
+ {
+ try
+ {
+ createChannelOverWire(channelId, prefetchHigh, prefetchLow, transacted);
+ }
+ catch (AMQException e)
+ {
+ deregisterSession(channelId);
+ throw new AMQException("Error reopening channel " + channelId + " after failover: " + e, e);
+ }
+ }
+
+ public void setFailoverPolicy(FailoverPolicy policy)
+ {
+ _failoverPolicy = policy;
+ }
+
+ public FailoverPolicy getFailoverPolicy()
+ {
+ return _failoverPolicy;
+ }
+
+ /**
+ * Returns an AMQQueueSessionAdaptor which wraps an AMQSession and throws IllegalStateExceptions where specified in
+ * the JMS spec
+ *
+ * @param transacted
+ * @param acknowledgeMode
+ *
+ * @return QueueSession
+ *
+ * @throws JMSException
+ */
+ public QueueSession createQueueSession(boolean transacted, int acknowledgeMode) throws JMSException
+ {
+ return new AMQQueueSessionAdaptor(createSession(transacted, acknowledgeMode));
+ }
+
+ /**
+ * Returns an AMQTopicSessionAdapter which wraps an AMQSession and throws IllegalStateExceptions where specified in
+ * the JMS spec
+ *
+ * @param transacted
+ * @param acknowledgeMode
+ *
+ * @return TopicSession
+ *
+ * @throws JMSException
+ */
+ public TopicSession createTopicSession(boolean transacted, int acknowledgeMode) throws JMSException
+ {
+ return new AMQTopicSessionAdaptor(createSession(transacted, acknowledgeMode));
+ }
+
+ private boolean channelLimitReached()
+ {
+ return (_maximumChannelCount != 0) && (_sessions.size() == _maximumChannelCount);
+ }
+
+ public String getClientID() throws JMSException
+ {
+ checkNotClosed();
+
+ return _clientName;
+ }
+
+ public void setClientID(String clientID) throws JMSException
+ {
+ checkNotClosed();
+ // in AMQP it is not possible to change the client ID. If one is not specified
+ // upon connection construction, an id is generated automatically. Therefore
+ // we can always throw an exception.
+ throw new IllegalStateException("Client name cannot be changed after being set");
+ }
+
+ public ConnectionMetaData getMetaData() throws JMSException
+ {
+ checkNotClosed();
+
+ return _connectionMetaData;
+
+ }
+
+ public ExceptionListener getExceptionListener() throws JMSException
+ {
+ checkNotClosed();
+
+ return _exceptionListener;
+ }
+
+ public void setExceptionListener(ExceptionListener listener) throws JMSException
+ {
+ checkNotClosed();
+ _exceptionListener = listener;
+ }
+
+ /**
+ * Start the connection, i.e. start flowing messages. Note that this method must be called only from a single thread
+ * and is not thread safe (which is legal according to the JMS specification).
+ *
+ * @throws JMSException
+ */
+ public void start() throws JMSException
+ {
+ checkNotClosed();
+ if (!_started)
+ {
+ final Iterator it = _sessions.entrySet().iterator();
+ while (it.hasNext())
+ {
+ final AMQSession s = (AMQSession) ((Map.Entry) it.next()).getValue();
+ try
+ {
+ s.start();
+ }
+ catch (AMQException e)
+ {
+ throw new JMSAMQException(e);
+ }
+ }
+
+ _started = true;
+ }
+ }
+
+ public void stop() throws JMSException
+ {
+ checkNotClosed();
+ if (_started)
+ {
+ for (Iterator i = _sessions.values().iterator(); i.hasNext();)
+ {
+ try
+ {
+ ((AMQSession) i.next()).stop();
+ }
+ catch (AMQException e)
+ {
+ throw new JMSAMQException(e);
+ }
+ }
+
+ _started = false;
+ }
+ }
+
+ public void close() throws JMSException
+ {
+ close(DEFAULT_TIMEOUT);
+ }
+
+ public void close(long timeout) throws JMSException
+ {
+ close(new ArrayList<AMQSession>(_sessions.values()),timeout);
+ }
+
+ public void close(List<AMQSession> sessions, long timeout) throws JMSException
+ {
+ synchronized(_sessionCreationLock)
+ {
+ if(!sessions.isEmpty())
+ {
+ AMQSession session = sessions.remove(0);
+ synchronized(session.getMessageDeliveryLock())
+ {
+ close(sessions, timeout);
+ }
+ }
+ else
+ {
+ synchronized (getFailoverMutex())
+ {
+ if (!_closed.getAndSet(true))
+ {
+ try
+ {
+ long startCloseTime = System.currentTimeMillis();
+
+ _taskPool.shutdown();
+ closeAllSessions(null, timeout, startCloseTime);
+
+ if (!_taskPool.isTerminated())
+ {
+ try
+ {
+ // adjust timeout
+ long taskPoolTimeout = adjustTimeout(timeout, startCloseTime);
+
+ _taskPool.awaitTermination(taskPoolTimeout, TimeUnit.MILLISECONDS);
+ }
+ catch (InterruptedException e)
+ {
+ _logger.info("Interrupted while shutting down connection thread pool.");
+ }
+ }
+
+ // adjust timeout
+ timeout = adjustTimeout(timeout, startCloseTime);
+
+ _protocolHandler.closeConnection(timeout);
+
+ //If the taskpool hasn't shutdown by now then give it shutdownNow.
+ // This will interupt any running tasks.
+ if (!_taskPool.isTerminated())
+ {
+ List<Runnable> tasks = _taskPool.shutdownNow();
+ for (Runnable r : tasks)
+ {
+ _logger.warn("Connection close forced taskpool to prevent execution:" + r);
+ }
+ }
+ }
+ catch (AMQException e)
+ {
+ JMSException jmse = new JMSException("Error closing connection: " + e);
+ jmse.setLinkedException(e);
+ throw jmse;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ private long adjustTimeout(long timeout, long startTime)
+ {
+ long now = System.currentTimeMillis();
+ timeout -= now - startTime;
+ if (timeout < 0)
+ {
+ timeout = 0;
+ }
+
+ return timeout;
+ }
+
+ /**
+ * Marks all sessions and their children as closed without sending any protocol messages. Useful when you need to
+ * mark objects "visible" in userland as closed after failover or other significant event that impacts the
+ * connection. <p/> The caller must hold the failover mutex before calling this method.
+ */
+ private void markAllSessionsClosed()
+ {
+ final LinkedList sessionCopy = new LinkedList(_sessions.values());
+ final Iterator it = sessionCopy.iterator();
+ while (it.hasNext())
+ {
+ final AMQSession session = (AMQSession) it.next();
+
+ session.markClosed();
+ }
+
+ _sessions.clear();
+ }
+
+ /**
+ * Close all the sessions, either due to normal connection closure or due to an error occurring.
+ *
+ * @param cause if not null, the error that is causing this shutdown <p/> The caller must hold the failover mutex
+ * before calling this method.
+ */
+ private void closeAllSessions(Throwable cause, long timeout, long starttime) throws JMSException
+ {
+ final LinkedList sessionCopy = new LinkedList(_sessions.values());
+ final Iterator it = sessionCopy.iterator();
+ JMSException sessionException = null;
+ while (it.hasNext())
+ {
+ final AMQSession session = (AMQSession) it.next();
+ if (cause != null)
+ {
+ session.closed(cause);
+ }
+ else
+ {
+ try
+ {
+ if (starttime != -1)
+ {
+ timeout = adjustTimeout(timeout, starttime);
+ }
+
+ session.close(timeout);
+ }
+ catch (JMSException e)
+ {
+ _logger.error("Error closing session: " + e);
+ sessionException = e;
+ }
+ }
+ }
+
+ _sessions.clear();
+ if (sessionException != null)
+ {
+ throw sessionException;
+ }
+ }
+
+ public ConnectionConsumer createConnectionConsumer(Destination destination, String messageSelector,
+ ServerSessionPool sessionPool, int maxMessages) throws JMSException
+ {
+ checkNotClosed();
+
+ return null;
+ }
+
+ public ConnectionConsumer createConnectionConsumer(Queue queue, String messageSelector, ServerSessionPool sessionPool,
+ int maxMessages) throws JMSException
+ {
+ checkNotClosed();
+
+ return null;
+ }
+
+ public ConnectionConsumer createConnectionConsumer(Topic topic, String messageSelector, ServerSessionPool sessionPool,
+ int maxMessages) throws JMSException
+ {
+ checkNotClosed();
+
+ return null;
+ }
+
+ public ConnectionConsumer createDurableConnectionConsumer(Topic topic, String subscriptionName, String messageSelector,
+ ServerSessionPool sessionPool, int maxMessages) throws JMSException
+ {
+ // TODO Auto-generated method stub
+ checkNotClosed();
+
+ return null;
+ }
+
+ public long getMaximumChannelCount() throws JMSException
+ {
+ checkNotClosed();
+
+ return _maximumChannelCount;
+ }
+
+ public void setConnectionListener(ConnectionListener listener)
+ {
+ _connectionListener = listener;
+ }
+
+ public ConnectionListener getConnectionListener()
+ {
+ return _connectionListener;
+ }
+
+ public void setMaximumChannelCount(long maximumChannelCount)
+ {
+ _maximumChannelCount = maximumChannelCount;
+ }
+
+ public void setMaximumFrameSize(long frameMax)
+ {
+ _maximumFrameSize = frameMax;
+ }
+
+ public long getMaximumFrameSize()
+ {
+ return _maximumFrameSize;
+ }
+
+ public Map getSessions()
+ {
+ return _sessions;
+ }
+
+ public String getUsername()
+ {
+ return _username;
+ }
+
+ public String getPassword()
+ {
+ return _password;
+ }
+
+ public String getVirtualHost()
+ {
+ return _virtualHost;
+ }
+
+ public AMQProtocolHandler getProtocolHandler()
+ {
+ return _protocolHandler;
+ }
+
+ public boolean started()
+ {
+ return _started;
+ }
+
+ public void bytesSent(long writtenBytes)
+ {
+ if (_connectionListener != null)
+ {
+ _connectionListener.bytesSent(writtenBytes);
+ }
+ }
+
+ public void bytesReceived(long receivedBytes)
+ {
+ if (_connectionListener != null)
+ {
+ _connectionListener.bytesReceived(receivedBytes);
+ }
+ }
+
+ /**
+ * Fire the preFailover event to the registered connection listener (if any)
+ *
+ * @param redirect true if this is the result of a redirect request rather than a connection error
+ *
+ * @return true if no listener or listener does not veto change
+ */
+ public boolean firePreFailover(boolean redirect)
+ {
+ boolean proceed = true;
+ if (_connectionListener != null)
+ {
+ proceed = _connectionListener.preFailover(redirect);
+ }
+
+ return proceed;
+ }
+
+ /**
+ * Fire the preResubscribe event to the registered connection listener (if any). If the listener vetoes
+ * resubscription then all the sessions are closed.
+ *
+ * @return true if no listener or listener does not veto resubscription.
+ *
+ * @throws JMSException
+ */
+ public boolean firePreResubscribe() throws JMSException
+ {
+ if (_connectionListener != null)
+ {
+ boolean resubscribe = _connectionListener.preResubscribe();
+ if (!resubscribe)
+ {
+ markAllSessionsClosed();
+ }
+
+ return resubscribe;
+ }
+ else
+ {
+ return true;
+ }
+ }
+
+ /** Fires a failover complete event to the registered connection listener (if any). */
+ public void fireFailoverComplete()
+ {
+ if (_connectionListener != null)
+ {
+ _connectionListener.failoverComplete();
+ }
+ }
+
+ /**
+ * In order to protect the consistency of the connection and its child sessions, consumers and producers, the
+ * "failover mutex" must be held when doing any operations that could be corrupted during failover.
+ *
+ * @return a mutex. Guaranteed never to change for the lifetime of this connection even if failover occurs.
+ */
+ public final Object getFailoverMutex()
+ {
+ return _failoverMutex;
+ }
+
+ /**
+ * If failover is taking place this will block until it has completed. If failover is not taking place it will
+ * return immediately.
+ *
+ * @throws InterruptedException
+ */
+ public void blockUntilNotFailingOver() throws InterruptedException
+ {
+ _protocolHandler.blockUntilNotFailingOver();
+ }
+
+ /**
+ * Invoked by the AMQProtocolSession when a protocol session exception has occurred. This method sends the exception
+ * to a JMS exception listener, if configured, and propagates the exception to sessions, which in turn will
+ * propagate to consumers. This allows synchronous consumers to have exceptions thrown to them.
+ *
+ * @param cause the exception
+ */
+ public void exceptionReceived(Throwable cause)
+ {
+
+ if (_logger.isDebugEnabled())
+ {
+ _logger.debug("exceptionReceived done by:" + Thread.currentThread().getName(), cause);
+ }
+
+ final JMSException je;
+ if (cause instanceof JMSException)
+ {
+ je = (JMSException) cause;
+ }
+ else
+ {
+ if (cause instanceof AMQException)
+ {
+ je =
+ new JMSException(Integer.toString(((AMQException) cause).getErrorCode().getCode()),
+ "Exception thrown against " + toString() + ": " + cause);
+ }
+ else
+ {
+ je = new JMSException("Exception thrown against " + toString() + ": " + cause);
+ }
+
+ if (cause instanceof Exception)
+ {
+ je.setLinkedException((Exception) cause);
+ }
+ }
+
+ // 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)
+ {
+ _closed.set(true);
+ }
+
+ if (_exceptionListener != null)
+ {
+ _exceptionListener.onException(je);
+ }
+ else
+ {
+ _logger.error("Throwable Received but no listener set: " + cause.getMessage());
+ }
+
+ if (!(cause instanceof AMQUndeliveredException) && !(cause instanceof AMQAuthenticationException))
+ {
+ try
+ {
+ if (_logger.isInfoEnabled())
+ {
+ _logger.info("Closing AMQConnection due to :" + cause.getMessage());
+ }
+
+ _closed.set(true);
+ closeAllSessions(cause, -1, -1); // FIXME: when doing this end up with RejectedExecutionException from executor.
+ }
+ catch (JMSException e)
+ {
+ _logger.error("Error closing all sessions: " + e, e);
+ }
+
+ }
+ else
+ {
+ _logger.info("Not a hard-error connection not closing: " + cause.getMessage());
+ }
+ }
+
+ void registerSession(int channelId, AMQSession session)
+ {
+ _sessions.put(channelId, session);
+ }
+
+ void deregisterSession(int channelId)
+ {
+ _sessions.remove(channelId);
+ }
+
+ /**
+ * 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.
+ */
+ public void resubscribeSessions() throws JMSException, AMQException, FailoverException
+ {
+ ArrayList sessions = new ArrayList(_sessions.values());
+ _logger.info(MessageFormat.format("Resubscribing sessions = {0} sessions.size={1}", sessions, sessions.size())); // FIXME: removeKey?
+ for (Iterator it = sessions.iterator(); it.hasNext();)
+ {
+ AMQSession s = (AMQSession) it.next();
+ // _protocolHandler.addSessionByChannel(s.getChannelId(), s);
+ reopenChannel(s.getChannelId(), s.getDefaultPrefetchHigh(), s.getDefaultPrefetchLow(), s.getTransacted());
+ s.resubscribe();
+ }
+ }
+
+ public String toString()
+ {
+ StringBuffer buf = new StringBuffer("AMQConnection:\n");
+ if (_failoverPolicy.getCurrentBrokerDetails() == null)
+ {
+ buf.append("No active broker connection");
+ }
+ else
+ {
+ BrokerDetails bd = _failoverPolicy.getCurrentBrokerDetails();
+ buf.append("Host: ").append(String.valueOf(bd.getHost()));
+ buf.append("\nPort: ").append(String.valueOf(bd.getPort()));
+ }
+
+ buf.append("\nVirtual Host: ").append(String.valueOf(_virtualHost));
+ buf.append("\nClient ID: ").append(String.valueOf(_clientName));
+ buf.append("\nActive session count: ").append((_sessions == null) ? 0 : _sessions.size());
+
+ return buf.toString();
+ }
+
+ public String toURL()
+ {
+ return _connectionURL.toString();
+ }
+
+ public Reference getReference() throws NamingException
+ {
+ return new Reference(AMQConnection.class.getName(), new StringRefAddr(AMQConnection.class.getName(), toURL()),
+ AMQConnectionFactory.class.getName(), null); // factory location
+ }
+
+ public SSLConfiguration getSSLConfiguration()
+ {
+ return _sslConfiguration;
+ }
+
+ public AMQShortString getDefaultTopicExchangeName()
+ {
+ return _defaultTopicExchangeName;
+ }
+
+ public void setDefaultTopicExchangeName(AMQShortString defaultTopicExchangeName)
+ {
+ _defaultTopicExchangeName = defaultTopicExchangeName;
+ }
+
+ public AMQShortString getDefaultQueueExchangeName()
+ {
+ return _defaultQueueExchangeName;
+ }
+
+ public void setDefaultQueueExchangeName(AMQShortString defaultQueueExchangeName)
+ {
+ _defaultQueueExchangeName = defaultQueueExchangeName;
+ }
+
+ public AMQShortString getTemporaryTopicExchangeName()
+ {
+ return _temporaryTopicExchangeName;
+ }
+
+ public AMQShortString getTemporaryQueueExchangeName()
+ {
+ return _temporaryQueueExchangeName; // To change body of created methods use File | Settings | File Templates.
+ }
+
+ public void setTemporaryTopicExchangeName(AMQShortString temporaryTopicExchangeName)
+ {
+ _temporaryTopicExchangeName = temporaryTopicExchangeName;
+ }
+
+ public void setTemporaryQueueExchangeName(AMQShortString temporaryQueueExchangeName)
+ {
+ _temporaryQueueExchangeName = temporaryQueueExchangeName;
+ }
+
+ public void performConnectionTask(Runnable task)
+ {
+ _taskPool.execute(task);
+ }
+
+ public AMQSession getSession(int channelId)
+ {
+ return _sessions.get(channelId);
+ }
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/client/AMQConnectionFactory.java b/Final/java/client/src/main/java/org/apache/qpid/client/AMQConnectionFactory.java
new file mode 100644
index 0000000000..7c0803a61a
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/AMQConnectionFactory.java
@@ -0,0 +1,409 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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 java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.Hashtable;
+import java.util.UUID;
+
+import javax.jms.Connection;
+import javax.jms.ConnectionFactory;
+import javax.jms.JMSException;
+import javax.jms.QueueConnection;
+import javax.jms.QueueConnectionFactory;
+import javax.jms.TopicConnection;
+import javax.jms.TopicConnectionFactory;
+import javax.naming.Context;
+import javax.naming.Name;
+import javax.naming.NamingException;
+import javax.naming.RefAddr;
+import javax.naming.Reference;
+import javax.naming.Referenceable;
+import javax.naming.StringRefAddr;
+import javax.naming.spi.ObjectFactory;
+
+import org.apache.qpid.jms.ConnectionURL;
+import org.apache.qpid.url.AMQBindingURL;
+import org.apache.qpid.url.URLSyntaxException;
+
+
+public class AMQConnectionFactory implements ConnectionFactory, QueueConnectionFactory, TopicConnectionFactory, ObjectFactory, Referenceable
+{
+ private String _host;
+ private int _port;
+ private String _defaultUsername;
+ private String _defaultPassword;
+ private String _virtualPath;
+
+ private ConnectionURL _connectionDetails;
+ private SSLConfiguration _sslConfig;
+
+ public AMQConnectionFactory()
+ {
+ }
+
+ public AMQConnectionFactory(String url) throws URLSyntaxException
+ {
+ _connectionDetails = new AMQConnectionURL(url);
+ }
+
+ public AMQConnectionFactory(ConnectionURL url)
+ {
+ _connectionDetails = url;
+ }
+
+ public AMQConnectionFactory(String broker, String username, String password,
+ String clientName, String virtualHost) throws URLSyntaxException
+ {
+ this(new AMQConnectionURL(ConnectionURL.AMQ_PROTOCOL + "://" +
+ username + ":" + password + "@" + clientName + "/" +
+ virtualHost + "?brokerlist='" + broker + "'"));
+ }
+
+ public AMQConnectionFactory(String host, int port, String virtualPath)
+ {
+ this(host, port, "guest", "guest", virtualPath);
+ }
+
+ public AMQConnectionFactory(String host, int port, String defaultUsername, String defaultPassword,
+ String virtualPath)
+ {
+ _host = host;
+ _port = port;
+ _defaultUsername = defaultUsername;
+ _defaultPassword = defaultPassword;
+ _virtualPath = virtualPath;
+
+//todo when setting Host/Port has been resolved then we can use this otherwise those methods won't work with the following line.
+// _connectionDetails = new AMQConnectionURL(
+// ConnectionURL.AMQ_PROTOCOL + "://" +
+// _defaultUsername + ":" + _defaultPassword + "@" +
+// virtualPath + "?brokerlist='tcp://" + host + ":" + port + "'");
+ }
+
+ /**
+ * @return The _defaultPassword.
+ */
+ public final String getDefaultPassword(String password)
+ {
+ if (_connectionDetails != null)
+ {
+ return _connectionDetails.getPassword();
+ }
+ else
+ {
+ return _defaultPassword;
+ }
+ }
+
+ /**
+ * @param password The _defaultPassword to set.
+ */
+ public final void setDefaultPassword(String password)
+ {
+ if (_connectionDetails != null)
+ {
+ _connectionDetails.setPassword(password);
+ }
+ _defaultPassword = password;
+ }
+
+ /**
+ * Getter for SSLConfiguration
+ *
+ * @return SSLConfiguration if set, otherwise null
+ */
+ public final SSLConfiguration getSSLConfiguration()
+ {
+ return _sslConfig;
+ }
+
+ /**
+ * Setter for SSLConfiguration
+ *
+ * @param sslConfig config to store
+ */
+ public final void setSSLConfiguration(SSLConfiguration sslConfig)
+ {
+ _sslConfig = sslConfig;
+ }
+
+ /**
+ * @return The _defaultPassword.
+ */
+ public final String getDefaultUsername(String password)
+ {
+ if (_connectionDetails != null)
+ {
+ return _connectionDetails.getUsername();
+ }
+ else
+ {
+ return _defaultUsername;
+ }
+ }
+
+ /**
+ * @param username The _defaultUsername to set.
+ */
+ public final void setDefaultUsername(String username)
+ {
+ if (_connectionDetails != null)
+ {
+ _connectionDetails.setUsername(username);
+ }
+ _defaultUsername = username;
+ }
+
+ /**
+ * @return The _host .
+ */
+ public final String getHost()
+ {
+ //todo this doesn't make sense in a multi broker URL as we have no current as that is done by AMQConnection
+ return _host;
+ }
+
+ /**
+ * @param host The _host to set.
+ */
+ public final void setHost(String host)
+ {
+ //todo if _connectionDetails is set then run _connectionDetails.addBrokerDetails()
+ // Should perhaps have this method changed to setBroker(host,port)
+ _host = host;
+ }
+
+ /**
+ * @return _port The _port to set.
+ */
+ public final int getPort()
+ {
+ //todo see getHost
+ return _port;
+ }
+
+ /**
+ * @param port The port to set.
+ */
+ public final void setPort(int port)
+ {
+ //todo see setHost
+ _port = port;
+ }
+
+ /**
+ * @return he _virtualPath.
+ */
+ public final String getVirtualPath()
+ {
+ if (_connectionDetails != null)
+ {
+ return _connectionDetails.getVirtualHost();
+ }
+ else
+ {
+ return _virtualPath;
+ }
+ }
+
+ /**
+ * @param path The _virtualPath to set.
+ */
+ public final void setVirtualPath(String path)
+ {
+ if (_connectionDetails != null)
+ {
+ _connectionDetails.setVirtualHost(path);
+ }
+
+ _virtualPath = path;
+ }
+
+ static String getUniqueClientID()
+ {
+ try
+ {
+ InetAddress addr = InetAddress.getLocalHost();
+ return addr.getHostName() + System.currentTimeMillis();
+ }
+ catch (UnknownHostException e)
+ {
+ return "UnknownHost" + UUID.randomUUID();
+ }
+ }
+
+ public Connection createConnection() throws JMSException
+ {
+ try
+ {
+ if (_connectionDetails != null)
+ {
+ if (_connectionDetails.getClientName() == null || _connectionDetails.getClientName().equals(""))
+ {
+ _connectionDetails.setClientName(getUniqueClientID());
+ }
+ return new AMQConnection(_connectionDetails, _sslConfig);
+ }
+ else
+ {
+ return new AMQConnection(_host, _port, _defaultUsername, _defaultPassword, getUniqueClientID(),
+ _virtualPath);
+ }
+ }
+ catch (Exception e)
+ {
+ JMSException jmse = new JMSException("Error creating connection: " + e.getMessage());
+ jmse.setLinkedException(e);
+ throw jmse;
+ }
+
+
+ }
+
+ public Connection createConnection(String userName, String password) throws JMSException
+ {
+ try
+ {
+ if (_connectionDetails != null)
+ {
+ _connectionDetails.setUsername(userName);
+ _connectionDetails.setPassword(password);
+
+ if (_connectionDetails.getClientName() == null || _connectionDetails.getClientName().equals(""))
+ {
+ _connectionDetails.setClientName(getUniqueClientID());
+ }
+ return new AMQConnection(_connectionDetails, _sslConfig);
+ }
+ else
+ {
+ return new AMQConnection(_host, _port, userName, password, getUniqueClientID(), _virtualPath);
+ }
+ }
+ catch (Exception e)
+ {
+ JMSException jmse = new JMSException("Error creating connection: " + e.getMessage());
+ jmse.setLinkedException(e);
+ throw jmse;
+ }
+ }
+
+ public QueueConnection createQueueConnection() throws JMSException
+ {
+ return (QueueConnection) createConnection();
+ }
+
+ public QueueConnection createQueueConnection(String username, String password) throws JMSException
+ {
+ return (QueueConnection) createConnection(username, password);
+ }
+
+ public TopicConnection createTopicConnection() throws JMSException
+ {
+ return (TopicConnection) createConnection();
+ }
+
+ public TopicConnection createTopicConnection(String username, String password) throws JMSException
+ {
+ return (TopicConnection) createConnection(username, password);
+ }
+
+
+ public ConnectionURL getConnectionURL()
+ {
+ return _connectionDetails;
+ }
+
+ /**
+ * JNDI interface to create objects from References.
+ *
+ * @param obj The Reference from JNDI
+ * @param name
+ * @param ctx
+ * @param env
+ *
+ * @return AMQConnection,AMQTopic,AMQQueue, or AMQConnectionFactory.
+ *
+ * @throws Exception
+ */
+ public Object getObjectInstance(Object obj, Name name, Context ctx,
+ Hashtable env) throws Exception
+ {
+ if (obj instanceof Reference)
+ {
+ Reference ref = (Reference) obj;
+
+ if (ref.getClassName().equals(AMQConnection.class.getName()))
+ {
+ RefAddr addr = ref.get(AMQConnection.class.getName());
+
+ if (addr != null)
+ {
+ return new AMQConnection((String) addr.getContent());
+ }
+ }
+
+ if (ref.getClassName().equals(AMQQueue.class.getName()))
+ {
+ RefAddr addr = ref.get(AMQQueue.class.getName());
+
+ if (addr != null)
+ {
+ return new AMQQueue(new AMQBindingURL((String) addr.getContent()));
+ }
+ }
+
+ if (ref.getClassName().equals(AMQTopic.class.getName()))
+ {
+ RefAddr addr = ref.get(AMQTopic.class.getName());
+
+ if (addr != null)
+ {
+ return new AMQTopic(new AMQBindingURL((String) addr.getContent()));
+ }
+ }
+
+ if (ref.getClassName().equals(AMQConnectionFactory.class.getName()))
+ {
+ RefAddr addr = ref.get(AMQConnectionFactory.class.getName());
+
+ if (addr != null)
+ {
+ return new AMQConnectionFactory(new AMQConnectionURL((String) addr.getContent()));
+ }
+ }
+
+ }
+ return null;
+ }
+
+
+ public Reference getReference() throws NamingException
+ {
+ return new Reference(
+ AMQConnectionFactory.class.getName(),
+ new StringRefAddr(AMQConnectionFactory.class.getName(), _connectionDetails.getURL()),
+ AMQConnectionFactory.class.getName(),
+ null); // factory location
+ }
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/client/AMQConnectionURL.java b/Final/java/client/src/main/java/org/apache/qpid/client/AMQConnectionURL.java
new file mode 100644
index 0000000000..24f5ead2d0
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/AMQConnectionURL.java
@@ -0,0 +1,455 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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.jms.BrokerDetails;
+import org.apache.qpid.jms.ConnectionURL;
+import org.apache.qpid.url.URLHelper;
+import org.apache.qpid.url.URLSyntaxException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.StringTokenizer;
+
+public class AMQConnectionURL implements ConnectionURL
+{
+ private static final Logger _logger = LoggerFactory.getLogger(AMQConnectionURL.class);
+
+ private String _url;
+ private String _failoverMethod;
+ private HashMap<String, String> _failoverOptions;
+ private HashMap<String, String> _options;
+ private List<BrokerDetails> _brokers;
+ private String _clientName;
+ private String _username;
+ private String _password;
+ private String _virtualHost;
+ private AMQShortString _defaultQueueExchangeName;
+ private AMQShortString _defaultTopicExchangeName;
+ private AMQShortString _temporaryTopicExchangeName;
+ private AMQShortString _temporaryQueueExchangeName;
+
+ public AMQConnectionURL(String fullURL) throws URLSyntaxException
+ {
+ _url = fullURL;
+ _options = new HashMap<String, String>();
+ _brokers = new LinkedList<BrokerDetails>();
+ _failoverOptions = new HashMap<String, String>();
+
+ // Connection URL format
+ // amqp://[user:pass@][clientid]/virtualhost?brokerlist='tcp://host:port?option=\'value\',option=\'value\';vm://:3/virtualpath?option=\'value\'',failover='method?option=\'value\',option='value''"
+ // Options are of course optional except for requiring a single broker in the broker list.
+ try
+ {
+ URI connection = new URI(fullURL);
+
+ if ((connection.getScheme() == null) || !(connection.getScheme().equalsIgnoreCase(AMQ_PROTOCOL)))
+ {
+ throw new URISyntaxException(fullURL, "Not an AMQP URL");
+ }
+
+ if ((connection.getHost() == null) || connection.getHost().equals(""))
+ {
+ String uid = AMQConnectionFactory.getUniqueClientID();
+ if (uid == null)
+ {
+ throw URLHelper.parseError(-1, "Client Name not specified", fullURL);
+ }
+ else
+ {
+ setClientName(uid);
+ }
+
+ }
+ else
+ {
+ setClientName(connection.getHost());
+ }
+
+ String userInfo = connection.getUserInfo();
+
+ if (userInfo == null)
+ {
+ // Fix for Java 1.5 which doesn't parse UserInfo for non http URIs
+ userInfo = connection.getAuthority();
+
+ if (userInfo != null)
+ {
+ int atIndex = userInfo.indexOf('@');
+
+ if (atIndex != -1)
+ {
+ userInfo = userInfo.substring(0, atIndex);
+ }
+ else
+ {
+ userInfo = null;
+ }
+ }
+
+ }
+
+ if (userInfo == null)
+ {
+ throw URLHelper.parseError(AMQ_PROTOCOL.length() + 3, "User information not found on url", fullURL);
+ }
+ else
+ {
+ parseUserInfo(userInfo);
+ }
+
+ String virtualHost = connection.getPath();
+
+ if ((virtualHost != null) && (!virtualHost.equals("")))
+ {
+ setVirtualHost(virtualHost);
+ }
+ else
+ {
+ int authLength = connection.getAuthority().length();
+ int start = AMQ_PROTOCOL.length() + 3;
+ int testIndex = start + authLength;
+ if ((testIndex < fullURL.length()) && (fullURL.charAt(testIndex) == '?'))
+ {
+ throw URLHelper.parseError(start, testIndex - start, "Virtual host found", fullURL);
+ }
+ else
+ {
+ throw URLHelper.parseError(-1, "Virtual host not specified", fullURL);
+ }
+
+ }
+
+ URLHelper.parseOptions(_options, connection.getQuery());
+
+ processOptions();
+ }
+ catch (URISyntaxException uris)
+ {
+ if (uris instanceof URLSyntaxException)
+ {
+ throw (URLSyntaxException) uris;
+ }
+
+ int slash = fullURL.indexOf("\\");
+
+ if (slash == -1)
+ {
+ throw URLHelper.parseError(uris.getIndex(), uris.getReason(), uris.getInput());
+ }
+ else
+ {
+ if ((slash != 0) && (fullURL.charAt(slash - 1) == ':'))
+ {
+ throw URLHelper.parseError(slash - 2, fullURL.indexOf('?') - slash + 2,
+ "Virtual host looks like a windows path, forward slash not allowed in URL", fullURL);
+ }
+ else
+ {
+ throw URLHelper.parseError(slash, "Forward slash not allowed in URL", fullURL);
+ }
+ }
+
+ }
+ }
+
+ private void parseUserInfo(String userinfo) throws URLSyntaxException
+ {
+ // user info = user:pass
+
+ int colonIndex = userinfo.indexOf(':');
+
+ if (colonIndex == -1)
+ {
+ throw URLHelper.parseError(AMQ_PROTOCOL.length() + 3, userinfo.length(),
+ "Null password in user information not allowed.", _url);
+ }
+ else
+ {
+ setUsername(userinfo.substring(0, colonIndex));
+ setPassword(userinfo.substring(colonIndex + 1));
+ }
+
+ }
+
+ private void processOptions() throws URLSyntaxException
+ {
+ if (_options.containsKey(OPTIONS_BROKERLIST))
+ {
+ String brokerlist = _options.get(OPTIONS_BROKERLIST);
+
+ // brokerlist tcp://host:port?option='value',option='value';vm://:3/virtualpath?option='value'
+ StringTokenizer st = new StringTokenizer(brokerlist, "" + URLHelper.BROKER_SEPARATOR);
+
+ while (st.hasMoreTokens())
+ {
+ String broker = st.nextToken();
+
+ _brokers.add(new AMQBrokerDetails(broker));
+ }
+
+ _options.remove(OPTIONS_BROKERLIST);
+ }
+
+ if (_options.containsKey(OPTIONS_FAILOVER))
+ {
+ String failover = _options.get(OPTIONS_FAILOVER);
+
+ // failover='method?option='value',option='value''
+
+ int methodIndex = failover.indexOf('?');
+
+ if (methodIndex > -1)
+ {
+ _failoverMethod = failover.substring(0, methodIndex);
+ URLHelper.parseOptions(_failoverOptions, failover.substring(methodIndex + 1));
+ }
+ else
+ {
+ _failoverMethod = failover;
+ }
+
+ _options.remove(OPTIONS_FAILOVER);
+ }
+
+ if (_options.containsKey(OPTIONS_DEFAULT_TOPIC_EXCHANGE))
+ {
+ _defaultTopicExchangeName = new AMQShortString(_options.get(OPTIONS_DEFAULT_TOPIC_EXCHANGE));
+ }
+
+ if (_options.containsKey(OPTIONS_DEFAULT_QUEUE_EXCHANGE))
+ {
+ _defaultQueueExchangeName = new AMQShortString(_options.get(OPTIONS_DEFAULT_QUEUE_EXCHANGE));
+ }
+
+ if (_options.containsKey(OPTIONS_TEMPORARY_QUEUE_EXCHANGE))
+ {
+ _temporaryQueueExchangeName = new AMQShortString(_options.get(OPTIONS_TEMPORARY_QUEUE_EXCHANGE));
+ }
+
+ if (_options.containsKey(OPTIONS_TEMPORARY_TOPIC_EXCHANGE))
+ {
+ _temporaryTopicExchangeName = new AMQShortString(_options.get(OPTIONS_TEMPORARY_TOPIC_EXCHANGE));
+ }
+ }
+
+ public String getURL()
+ {
+ return _url;
+ }
+
+ public String getFailoverMethod()
+ {
+ return _failoverMethod;
+ }
+
+ public String getFailoverOption(String key)
+ {
+ return _failoverOptions.get(key);
+ }
+
+ public void setFailoverOption(String key, String value)
+ {
+ _failoverOptions.put(key, value);
+ }
+
+ public int getBrokerCount()
+ {
+ return _brokers.size();
+ }
+
+ public BrokerDetails getBrokerDetails(int index)
+ {
+ if (index < _brokers.size())
+ {
+ return _brokers.get(index);
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ public void addBrokerDetails(BrokerDetails broker)
+ {
+ if (!(_brokers.contains(broker)))
+ {
+ _brokers.add(broker);
+ }
+ }
+
+ public List<BrokerDetails> getAllBrokerDetails()
+ {
+ return _brokers;
+ }
+
+ public String getClientName()
+ {
+ return _clientName;
+ }
+
+ public void setClientName(String clientName)
+ {
+ _clientName = clientName;
+ }
+
+ public String getUsername()
+ {
+ return _username;
+ }
+
+ public void setUsername(String username)
+ {
+ _username = username;
+ }
+
+ public String getPassword()
+ {
+ return _password;
+ }
+
+ public void setPassword(String password)
+ {
+ _password = password;
+ }
+
+ public String getVirtualHost()
+ {
+ return _virtualHost;
+ }
+
+ public void setVirtualHost(String virtuaHost)
+ {
+ _virtualHost = virtuaHost;
+ }
+
+ public String getOption(String key)
+ {
+ return _options.get(key);
+ }
+
+ public void setOption(String key, String value)
+ {
+ _options.put(key, value);
+ }
+
+ public AMQShortString getDefaultQueueExchangeName()
+ {
+ return _defaultQueueExchangeName;
+ }
+
+ public AMQShortString getDefaultTopicExchangeName()
+ {
+ return _defaultTopicExchangeName;
+ }
+
+ public AMQShortString getTemporaryQueueExchangeName()
+ {
+ return _temporaryQueueExchangeName;
+ }
+
+ public AMQShortString getTemporaryTopicExchangeName()
+ {
+ return _temporaryTopicExchangeName;
+ }
+
+ public String toString()
+ {
+ StringBuffer sb = new StringBuffer();
+
+ sb.append(AMQ_PROTOCOL);
+ sb.append("://");
+
+ if (_username != null)
+ {
+ sb.append(_username);
+
+ if (_password != null)
+ {
+ sb.append(':');
+ if (_logger.isDebugEnabled())
+ {
+ sb.append(_password);
+ }
+ else
+ {
+ sb.append("********");
+ }
+ }
+
+ sb.append('@');
+ }
+
+ sb.append(_clientName);
+
+ sb.append(_virtualHost);
+
+ sb.append(optionsToString());
+
+ return sb.toString();
+ }
+
+ private String optionsToString()
+ {
+ StringBuffer sb = new StringBuffer();
+
+ sb.append("?" + OPTIONS_BROKERLIST + "='");
+
+ for (BrokerDetails service : _brokers)
+ {
+ sb.append(service.toString());
+ sb.append(';');
+ }
+
+ sb.deleteCharAt(sb.length() - 1);
+ sb.append("'");
+
+ if (_failoverMethod != null)
+ {
+ sb.append(URLHelper.DEFAULT_OPTION_SEPERATOR);
+ sb.append(OPTIONS_FAILOVER + "='");
+ sb.append(_failoverMethod);
+ sb.append(URLHelper.printOptions(_failoverOptions));
+ sb.append("'");
+ }
+
+ return sb.toString();
+ }
+
+ public static void main(String[] args) throws URLSyntaxException
+ {
+ String url2 =
+ "amqp://ritchiem:bob@temp?brokerlist='tcp://localhost:5672;jcp://fancyserver:3000/',failover='roundrobin'";
+ // "amqp://user:pass@clientid/virtualhost?brokerlist='tcp://host:1?option1=\'value\',option2=\'value\';vm://:3?option1=\'value\'',failover='method?option1=\'value\',option2='value''";
+
+ ConnectionURL connectionurl2 = new AMQConnectionURL(url2);
+
+ System.out.println(url2);
+ System.out.println(connectionurl2);
+
+ }
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/client/AMQDestination.java b/Final/java/client/src/main/java/org/apache/qpid/client/AMQDestination.java
new file mode 100644
index 0000000000..cc5af07b20
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/AMQDestination.java
@@ -0,0 +1,451 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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.Destination;
+import javax.naming.NamingException;
+import javax.naming.Reference;
+import javax.naming.Referenceable;
+import javax.naming.StringRefAddr;
+
+import org.apache.qpid.exchange.ExchangeDefaults;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.url.AMQBindingURL;
+import org.apache.qpid.url.BindingURL;
+import org.apache.qpid.url.URLHelper;
+import org.apache.qpid.url.URLSyntaxException;
+
+
+public abstract class AMQDestination implements Destination, Referenceable
+{
+ protected final AMQShortString _exchangeName;
+
+ protected final AMQShortString _exchangeClass;
+
+ protected final AMQShortString _destinationName;
+
+ protected final boolean _isDurable;
+
+ protected final boolean _isExclusive;
+
+ protected final boolean _isAutoDelete;
+
+ private AMQShortString _queueName;
+
+ private String _url;
+ private AMQShortString _urlAsShortString;
+
+ private boolean _validated;
+
+ private byte[] _byteEncoding;
+ private static final int IS_DURABLE_MASK = 0x1;
+ private static final int IS_EXCLUSIVE_MASK = 0x2;
+ private static final int IS_AUTODELETE_MASK = 0x4;
+
+ public static final Integer QUEUE_TYPE = Integer.valueOf(1);
+ public static final Integer TOPIC_TYPE = Integer.valueOf(2);
+ public static final Integer UNKNOWN_TYPE = Integer.valueOf(3);
+
+ protected AMQDestination(String url) throws URLSyntaxException
+ {
+ this(new AMQBindingURL(url));
+ }
+
+ protected AMQDestination(BindingURL binding)
+ {
+ _exchangeName = binding.getExchangeName();
+ _exchangeClass = binding.getExchangeClass();
+ _destinationName = binding.getDestinationName();
+
+ _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());
+ }
+
+ protected AMQDestination(AMQShortString exchangeName, AMQShortString exchangeClass, AMQShortString destinationName, AMQShortString queueName)
+ {
+ this(exchangeName, exchangeClass, destinationName, false, false, queueName);
+ }
+
+ protected AMQDestination(AMQShortString exchangeName, AMQShortString exchangeClass, AMQShortString destinationName)
+ {
+ this(exchangeName, exchangeClass, destinationName, false, false, null);
+ }
+
+ protected AMQDestination(AMQShortString exchangeName, AMQShortString exchangeClass, AMQShortString destinationName, boolean isExclusive,
+ boolean isAutoDelete, AMQShortString queueName)
+ {
+ this(exchangeName, exchangeClass, destinationName, isExclusive, isAutoDelete, queueName, false);
+ }
+
+ protected AMQDestination(AMQShortString exchangeName, AMQShortString exchangeClass, AMQShortString destinationName, boolean isExclusive,
+ boolean isAutoDelete, AMQShortString queueName, boolean isDurable)
+ {
+ if (destinationName == null)
+ {
+ throw new IllegalArgumentException("Destination exchange must not be null");
+ }
+ if (exchangeName == null)
+ {
+ throw new IllegalArgumentException("Exchange exchange must not be null");
+ }
+ if (exchangeClass == null)
+ {
+ throw new IllegalArgumentException("Exchange class must not be null");
+ }
+ _exchangeName = exchangeName;
+ _exchangeClass = exchangeClass;
+ _destinationName = destinationName;
+ _isExclusive = isExclusive;
+ _isAutoDelete = isAutoDelete;
+ _queueName = queueName;
+ _isDurable = isDurable;
+ }
+
+ public AMQShortString getEncodedName()
+ {
+ if(_urlAsShortString == null)
+ {
+ toURL();
+ }
+ return _urlAsShortString;
+ }
+
+ public boolean isDurable()
+ {
+ return _isDurable;
+ }
+
+ public AMQShortString getExchangeName()
+ {
+ return _exchangeName;
+ }
+
+ public AMQShortString getExchangeClass()
+ {
+ return _exchangeClass;
+ }
+
+ public boolean isTopic()
+ {
+ return ExchangeDefaults.TOPIC_EXCHANGE_CLASS.equals(_exchangeClass);
+ }
+
+ public boolean isQueue()
+ {
+ return ExchangeDefaults.DIRECT_EXCHANGE_CLASS.equals(_exchangeClass);
+ }
+
+ public AMQShortString getDestinationName()
+ {
+ return _destinationName;
+ }
+
+ public String getQueueName()
+ {
+ return _queueName == null ? null : _queueName.toString();
+ }
+
+ public AMQShortString getAMQQueueName()
+ {
+ return _queueName;
+ }
+
+
+
+ public void setQueueName(AMQShortString queueName)
+ {
+
+ _queueName = queueName;
+ // calculated URL now out of date
+ _url = null;
+ _urlAsShortString = null;
+ _byteEncoding = null;
+ }
+
+ public abstract AMQShortString getRoutingKey();
+
+ public boolean isExclusive()
+ {
+ return _isExclusive;
+ }
+
+ public boolean isAutoDelete()
+ {
+ return _isAutoDelete;
+ }
+
+ public abstract boolean isNameRequired();
+
+ public String toString()
+ {
+ return toURL();
+
+ }
+
+ public boolean isValidated()
+ {
+ return _validated;
+ }
+
+ public void setValidated(boolean validated)
+ {
+ _validated = validated;
+ }
+
+ public String toURL()
+ {
+ String url = _url;
+ if(url == null)
+ {
+
+
+ StringBuffer sb = new StringBuffer();
+
+ sb.append(_exchangeClass);
+ sb.append("://");
+ sb.append(_exchangeName);
+
+ sb.append('/');
+
+ if (_destinationName != null)
+ {
+ sb.append(_destinationName);
+ }
+
+ sb.append('/');
+
+ if (_queueName != null)
+ {
+ sb.append(_queueName);
+ }
+
+ sb.append('?');
+
+ if (_isDurable)
+ {
+ sb.append(BindingURL.OPTION_DURABLE);
+ sb.append("='true'");
+ sb.append(URLHelper.DEFAULT_OPTION_SEPERATOR);
+ }
+
+ if (_isExclusive)
+ {
+ sb.append(BindingURL.OPTION_EXCLUSIVE);
+ sb.append("='true'");
+ sb.append(URLHelper.DEFAULT_OPTION_SEPERATOR);
+ }
+
+ if (_isAutoDelete)
+ {
+ sb.append(BindingURL.OPTION_AUTODELETE);
+ sb.append("='true'");
+ sb.append(URLHelper.DEFAULT_OPTION_SEPERATOR);
+ }
+
+ //removeKey the last char '?' if there is no options , ',' if there are.
+ sb.deleteCharAt(sb.length() - 1);
+ url = sb.toString();
+ _url = url;
+ _urlAsShortString = new AMQShortString(url);
+ }
+ return url;
+ }
+
+ public byte[] toByteEncoding()
+ {
+ byte[] encoding = _byteEncoding;
+ if(encoding == null)
+ {
+ int size = _exchangeClass.length() + 1 +
+ _exchangeName.length() + 1 +
+ (_destinationName == null ? 0 : _destinationName.length()) + 1 +
+ (_queueName == null ? 0 : _queueName.length()) + 1 +
+ 1;
+ encoding = new byte[size];
+ int pos = 0;
+
+ pos = _exchangeClass.writeToByteArray(encoding, pos);
+ pos = _exchangeName.writeToByteArray(encoding, pos);
+ if(_destinationName == null)
+ {
+ encoding[pos++] = (byte)0;
+ }
+ else
+ {
+ pos = _destinationName.writeToByteArray(encoding,pos);
+ }
+ if(_queueName == null)
+ {
+ encoding[pos++] = (byte)0;
+ }
+ else
+ {
+ pos = _queueName.writeToByteArray(encoding,pos);
+ }
+ byte options = 0;
+ if(_isDurable)
+ {
+ options |= IS_DURABLE_MASK;
+ }
+ if(_isExclusive)
+ {
+ options |= IS_EXCLUSIVE_MASK;
+ }
+ if(_isAutoDelete)
+ {
+ options |= IS_AUTODELETE_MASK;
+ }
+ encoding[pos] = options;
+
+
+ _byteEncoding = encoding;
+
+ }
+ return encoding;
+ }
+
+ public boolean equals(Object o)
+ {
+ if (this == o)
+ {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass())
+ {
+ return false;
+ }
+
+ final AMQDestination that = (AMQDestination) o;
+
+ if (!_destinationName.equals(that._destinationName))
+ {
+ return false;
+ }
+ if (!_exchangeClass.equals(that._exchangeClass))
+ {
+ return false;
+ }
+ if (!_exchangeName.equals(that._exchangeName))
+ {
+ return false;
+ }
+ if ((_queueName == null && that._queueName != null) ||
+ (_queueName != null && !_queueName.equals(that._queueName)))
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ public int hashCode()
+ {
+ int result;
+ result = _exchangeName.hashCode();
+ result = 29 * result + _exchangeClass.hashCode();
+ result = 29 * result + _destinationName.hashCode();
+ if (_queueName != null)
+ {
+ result = 29 * result + _queueName.hashCode();
+ }
+
+ return result;
+ }
+
+ public Reference getReference() throws NamingException
+ {
+ return new Reference(
+ this.getClass().getName(),
+ new StringRefAddr(this.getClass().getName(), toURL()),
+ AMQConnectionFactory.class.getName(),
+ null); // factory location
+ }
+
+
+ public static Destination createDestination(byte[] byteEncodedDestination)
+ {
+ AMQShortString exchangeClass;
+ AMQShortString exchangeName;
+ AMQShortString destinationName;
+ AMQShortString queueName;
+ boolean isDurable;
+ boolean isExclusive;
+ boolean isAutoDelete;
+
+ int pos = 0;
+ exchangeClass = AMQShortString.readFromByteArray(byteEncodedDestination, pos);
+ pos+= exchangeClass.length() + 1;
+ exchangeName = AMQShortString.readFromByteArray(byteEncodedDestination, pos);
+ pos+= exchangeName.length() + 1;
+ destinationName = AMQShortString.readFromByteArray(byteEncodedDestination, pos);
+ pos+= (destinationName == null ? 0 : destinationName.length()) + 1;
+ queueName = AMQShortString.readFromByteArray(byteEncodedDestination, pos);
+ pos+= (queueName == null ? 0 : queueName.length()) + 1;
+ int options = byteEncodedDestination[pos];
+ isDurable = (options & IS_DURABLE_MASK) != 0;
+ isExclusive = (options & IS_EXCLUSIVE_MASK) != 0;
+ isAutoDelete = (options & IS_AUTODELETE_MASK) != 0;
+
+ if (exchangeClass.equals(ExchangeDefaults.DIRECT_EXCHANGE_CLASS))
+ {
+ return new AMQQueue(exchangeName,destinationName,queueName,isExclusive,isAutoDelete,isDurable);
+ }
+ else if (exchangeClass.equals(ExchangeDefaults.TOPIC_EXCHANGE_CLASS))
+ {
+ return new AMQTopic(exchangeName,destinationName,isAutoDelete,queueName,isDurable);
+ }
+ else if (exchangeClass.equals(ExchangeDefaults.HEADERS_EXCHANGE_CLASS))
+ {
+ return new AMQHeadersExchange(destinationName);
+ }
+ else
+ {
+ throw new IllegalArgumentException("Unknown Exchange Class:" + exchangeClass);
+ }
+
+
+
+ }
+
+ public static Destination createDestination(BindingURL binding)
+ {
+ AMQShortString type = binding.getExchangeClass();
+
+ if (type.equals(ExchangeDefaults.DIRECT_EXCHANGE_CLASS))
+ {
+ return new AMQQueue(binding);
+ }
+ else if (type.equals(ExchangeDefaults.TOPIC_EXCHANGE_CLASS))
+ {
+ return new AMQTopic(binding);
+ }
+ else if (type.equals(ExchangeDefaults.HEADERS_EXCHANGE_CLASS))
+ {
+ return new AMQHeadersExchange(binding);
+ }
+ else
+ {
+ throw new IllegalArgumentException("Unknown Exchange Class:" + type + " in binding:" + binding);
+ }
+ }
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/client/AMQHeadersExchange.java b/Final/java/client/src/main/java/org/apache/qpid/client/AMQHeadersExchange.java
new file mode 100644
index 0000000000..1a2fe0d355
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/AMQHeadersExchange.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.client;
+
+import org.apache.qpid.exchange.ExchangeDefaults;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.url.BindingURL;
+
+/**
+ * A destination backed by a headers exchange
+ */
+public class AMQHeadersExchange extends AMQDestination
+{
+ public AMQHeadersExchange(BindingURL binding)
+ {
+ this(binding.getExchangeName());
+ }
+
+ public AMQHeadersExchange(String name)
+ {
+ this(new AMQShortString(name));
+ }
+
+ public AMQHeadersExchange(AMQShortString queueName)
+ {
+ super(queueName, ExchangeDefaults.HEADERS_EXCHANGE_CLASS, queueName, true, true, null);
+ }
+
+ public AMQShortString getRoutingKey()
+ {
+ return getDestinationName();
+ }
+
+ public boolean isNameRequired()
+ {
+ //Not sure what the best approach is here, probably to treat this like a topic
+ //and allow server to generate names. As it is AMQ specific it doesn't need to
+ //fit the JMS API expectations so this is not as yet critical.
+ return false;
+ }
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/client/AMQNoConsumersException.java b/Final/java/client/src/main/java/org/apache/qpid/client/AMQNoConsumersException.java
new file mode 100644
index 0000000000..54d5a0426f
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/AMQNoConsumersException.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.client;
+
+import org.apache.qpid.AMQUndeliveredException;
+import org.apache.qpid.protocol.AMQConstant;
+
+/**
+ * AMQNoConsumersException indicates failure to pass an immediate message to a consumer.
+ *
+ * <p/><table id="crc"><caption>CRC Card</caption>
+ * <tr><th> Responsibilities <th> Collaborations
+ * <tr><td> Represents failure to pass an immediate message to a consumer.
+ * <tr><td>
+ */
+public class AMQNoConsumersException extends AMQUndeliveredException
+{
+ public AMQNoConsumersException(String msg, Object bounced)
+ {
+ super(AMQConstant.NO_CONSUMERS, msg, bounced);
+ }
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/client/AMQNoRouteException.java b/Final/java/client/src/main/java/org/apache/qpid/client/AMQNoRouteException.java
new file mode 100644
index 0000000000..a314101acf
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/AMQNoRouteException.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.client;
+
+import org.apache.qpid.AMQUndeliveredException;
+import org.apache.qpid.protocol.AMQConstant;
+
+/**
+ * AMQNoRouteException indicates that a mandatory message could not be routed.
+ *
+ * <p/><table id="crc"><caption>CRC Card</caption>
+ * <tr><th> Responsibilities <th> Collaborations
+ * <tr><td> Represents failure to route a mandatory message.
+ * <tr><td>
+ */
+public class AMQNoRouteException extends AMQUndeliveredException
+{
+ public AMQNoRouteException(String msg, Object bounced)
+ {
+ super(AMQConstant.NO_ROUTE, msg, bounced);
+ }
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/client/AMQQueue.java b/Final/java/client/src/main/java/org/apache/qpid/client/AMQQueue.java
new file mode 100644
index 0000000000..9185bc87e8
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/AMQQueue.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.client;
+
+import javax.jms.Queue;
+import javax.jms.Connection;
+
+import org.apache.qpid.exchange.ExchangeDefaults;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.url.BindingURL;
+
+public class AMQQueue extends AMQDestination implements Queue
+{
+
+ /**
+ * Create a reference to a non temporary queue using a BindingURL object.
+ * Note this does not actually imply the queue exists.
+ * @param binding a BindingURL object
+ */
+ public AMQQueue(BindingURL binding)
+ {
+ super(binding);
+ }
+
+ /**
+ * Create a reference to a non temporary queue. Note this does not actually imply the queue exists.
+ * @param name the name of the queue
+ */
+ public AMQQueue(AMQShortString exchangeName, String name)
+ {
+ this(exchangeName, new AMQShortString(name));
+ }
+
+
+ /**
+ * Create a reference to a non temporary queue. Note this does not actually imply the queue exists.
+ * @param name the name of the queue
+ */
+ public AMQQueue(AMQShortString exchangeName, AMQShortString name)
+ {
+ this(exchangeName, name, false);
+ }
+
+ public AMQQueue(AMQShortString exchangeName, AMQShortString routingKey, AMQShortString queueName)
+ {
+ super(exchangeName, ExchangeDefaults.DIRECT_EXCHANGE_CLASS, routingKey, false,
+ false, queueName, false); }
+
+
+ /**
+ * Create a reference to a non temporary queue. Note this does not actually imply the queue exists.
+ * @param name the name of the queue
+ */
+ public AMQQueue(String exchangeName, String name)
+ {
+ this(new AMQShortString(exchangeName), new AMQShortString(name), false);
+ }
+
+
+ public AMQQueue(AMQConnection connection, String name)
+ {
+ this(connection.getDefaultQueueExchangeName(),name);
+ }
+
+ public AMQQueue(AMQConnection connection, String name, boolean temporary)
+ {
+ this(connection.getDefaultQueueExchangeName(), new AMQShortString(name),temporary);
+ }
+
+
+ /**
+ * Create a queue with a specified name.
+ *
+ * @param name the destination name (used in the routing key)
+ * @param temporary if true the broker will generate a queue name, also if true then the queue is autodeleted
+ * and exclusive
+ */
+ public AMQQueue(String exchangeName, String name, boolean temporary)
+ {
+ this(new AMQShortString(exchangeName), new AMQShortString(name),temporary);
+ }
+
+
+ /**
+ * Create a queue with a specified name.
+ *
+ * @param name the destination name (used in the routing key)
+ * @param temporary if true the broker will generate a queue name, also if true then the queue is autodeleted
+ * and exclusive
+ */
+ public AMQQueue(AMQShortString exchangeName, AMQShortString name, boolean temporary)
+ {
+ // queue name is set to null indicating that the broker assigns a name in the case of temporary queues
+ // temporary queues are typically used as response queues
+ this(exchangeName, name, temporary?null:name, temporary, temporary, !temporary);
+
+ }
+
+ /**
+ * Create a reference to a queue. Note this does not actually imply the queue exists.
+ * @param destinationName the queue name
+ * @param queueName the queue name
+ * @param exclusive true if the queue should only permit a single consumer
+ * @param autoDelete true if the queue should be deleted automatically when the last consumers detaches
+ */
+ public AMQQueue(AMQShortString exchangeName, AMQShortString destinationName, AMQShortString queueName, boolean exclusive, boolean autoDelete)
+ {
+ this(exchangeName, destinationName, queueName, exclusive, autoDelete, false);
+ }
+
+
+ public AMQQueue(AMQShortString exchangeName, AMQShortString destinationName, AMQShortString queueName, boolean exclusive, boolean autoDelete, boolean durable)
+ {
+ super(exchangeName, ExchangeDefaults.DIRECT_EXCHANGE_CLASS, destinationName, exclusive,
+ autoDelete, queueName, durable);
+ }
+
+
+
+ public AMQShortString getRoutingKey()
+ {
+ return getAMQQueueName();
+ }
+
+ public boolean isNameRequired()
+ {
+ //If the name is null, we require one to be generated by the client so that it will#
+ //remain valid if we failover (see BLZ-24)
+ return getQueueName() == null;
+ }
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/client/AMQQueueBrowser.java b/Final/java/client/src/main/java/org/apache/qpid/client/AMQQueueBrowser.java
new file mode 100644
index 0000000000..28e5992b26
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/AMQQueueBrowser.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.client;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+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;
+
+public class AMQQueueBrowser implements QueueBrowser
+{
+ private static final Logger _logger = LoggerFactory.getLogger(AMQQueueBrowser.class);
+
+ private AtomicBoolean _isClosed = new AtomicBoolean();
+ private final AMQSession _session;
+ private final AMQQueue _queue;
+ private final ArrayList<BasicMessageConsumer> _consumers = new ArrayList<BasicMessageConsumer>();
+ private final String _messageSelector;
+
+ AMQQueueBrowser(AMQSession session, AMQQueue queue, String messageSelector) throws JMSException
+ {
+ _session = session;
+ _queue = queue;
+ _messageSelector = ((messageSelector == null) || (messageSelector.trim().length() == 0)) ? null : messageSelector;
+ // Create Consumer to verify message selector.
+ BasicMessageConsumer consumer =
+ (BasicMessageConsumer) _session.createBrowserConsumer(_queue, _messageSelector, false);
+ consumer.close();
+ }
+
+ public Queue getQueue() throws JMSException
+ {
+ checkState();
+
+ return _queue;
+ }
+
+ private void checkState() throws JMSException
+ {
+ if (_isClosed.get())
+ {
+ throw new IllegalStateException("Queue Browser");
+ }
+
+ if (_session.isClosed())
+ {
+ throw new IllegalStateException("Session is closed");
+ }
+
+ }
+
+ public String getMessageSelector() throws JMSException
+ {
+
+ checkState();
+
+ return _messageSelector;
+ }
+
+ public Enumeration getEnumeration() throws JMSException
+ {
+ checkState();
+ final BasicMessageConsumer consumer =
+ (BasicMessageConsumer) _session.createBrowserConsumer(_queue, _messageSelector, false);
+ _consumers.add(consumer);
+
+ return new Enumeration()
+ {
+
+ Message _nextMessage = consumer.receive();
+
+ 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();
+ _logger.info("QB:nextElement received:" + _nextMessage);
+ }
+ catch (JMSException e)
+ {
+ _logger.warn("Exception caught while queue browsing", e);
+ _nextMessage = null;
+ }
+
+ return msg;
+ }
+ };
+ }
+
+ public void close() throws JMSException
+ {
+ for (BasicMessageConsumer consumer : _consumers)
+ {
+ consumer.close();
+ }
+
+ _consumers.clear();
+ }
+
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/client/AMQQueueSessionAdaptor.java b/Final/java/client/src/main/java/org/apache/qpid/client/AMQQueueSessionAdaptor.java
new file mode 100644
index 0000000000..a8c83d8868
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/AMQQueueSessionAdaptor.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.client;
+
+import java.io.Serializable;
+
+import javax.jms.BytesMessage;
+import javax.jms.Destination;
+import javax.jms.IllegalStateException;
+import javax.jms.JMSException;
+import javax.jms.MapMessage;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageListener;
+import javax.jms.MessageProducer;
+import javax.jms.ObjectMessage;
+import javax.jms.Queue;
+import javax.jms.QueueBrowser;
+import javax.jms.QueueReceiver;
+import javax.jms.QueueSender;
+import javax.jms.QueueSession;
+import javax.jms.Session;
+import javax.jms.StreamMessage;
+import javax.jms.TemporaryQueue;
+import javax.jms.TemporaryTopic;
+import javax.jms.TextMessage;
+import javax.jms.Topic;
+import javax.jms.TopicSubscriber;
+
+/**
+ * Need this adaptor class to conform to JMS spec and throw IllegalStateException
+ * from createDurableSubscriber, unsubscribe, createTopic & createTemporaryTopic
+ */
+public class AMQQueueSessionAdaptor implements QueueSession, AMQSessionAdapter
+{
+ //holds a session for delegation
+ protected final AMQSession _session;
+
+ /**
+ * Construct an adaptor with a session to wrap
+ * @param session
+ */
+ public AMQQueueSessionAdaptor(Session session)
+ {
+ _session = (AMQSession) session;
+ }
+
+ public TemporaryQueue createTemporaryQueue() throws JMSException {
+ return _session.createTemporaryQueue();
+ }
+
+ public Queue createQueue(String string) throws JMSException {
+ return _session.createQueue(string);
+ }
+
+ public QueueReceiver createReceiver(Queue queue) throws JMSException {
+ return _session.createReceiver(queue);
+ }
+
+ public QueueReceiver createReceiver(Queue queue, String string) throws JMSException {
+ return _session.createReceiver(queue, string);
+ }
+
+ public QueueSender createSender(Queue queue) throws JMSException {
+ return _session.createSender(queue);
+ }
+
+ public QueueBrowser createBrowser(Queue queue) throws JMSException {
+ return _session.createBrowser(queue);
+ }
+
+ public QueueBrowser createBrowser(Queue queue, String string) throws JMSException {
+ return _session.createBrowser(queue, string);
+ }
+
+ public BytesMessage createBytesMessage() throws JMSException {
+ return _session.createBytesMessage();
+ }
+
+ public MapMessage createMapMessage() throws JMSException {
+ return _session.createMapMessage();
+ }
+
+ public Message createMessage() throws JMSException {
+ return _session.createMessage();
+ }
+
+ public ObjectMessage createObjectMessage() throws JMSException {
+ return _session.createObjectMessage();
+ }
+
+ public ObjectMessage createObjectMessage(Serializable serializable) throws JMSException {
+ return _session.createObjectMessage(serializable);
+ }
+
+ public StreamMessage createStreamMessage() throws JMSException {
+ return _session.createStreamMessage();
+ }
+
+ public TextMessage createTextMessage() throws JMSException {
+ return _session.createTextMessage();
+ }
+
+ public TextMessage createTextMessage(String string) throws JMSException {
+ return _session.createTextMessage(string);
+ }
+
+ public boolean getTransacted() throws JMSException {
+ return _session.getTransacted();
+ }
+
+ public int getAcknowledgeMode() throws JMSException {
+ return _session.getAcknowledgeMode();
+ }
+
+ public void commit() throws JMSException {
+ _session.commit();
+ }
+
+ public void rollback() throws JMSException {
+ _session.rollback();
+ }
+
+ public void close() throws JMSException {
+ _session.close();
+ }
+
+ public void recover() throws JMSException {
+ _session.recover();
+ }
+
+ public MessageListener getMessageListener() throws JMSException {
+ return _session.getMessageListener();
+ }
+
+ public void setMessageListener(MessageListener messageListener) throws JMSException {
+ _session.setMessageListener(messageListener);
+ }
+
+ public void run() {
+ _session.run();
+ }
+
+ public MessageProducer createProducer(Destination destination) throws JMSException {
+ return _session.createProducer(destination);
+ }
+
+ public MessageConsumer createConsumer(Destination destination) throws JMSException {
+ return _session.createConsumer(destination);
+ }
+
+ public MessageConsumer createConsumer(Destination destination, String string) throws JMSException {
+ return _session.createConsumer(destination,string);
+ }
+
+ public MessageConsumer createConsumer(Destination destination, String string, boolean b) throws JMSException {
+ return _session.createConsumer(destination,string,b);
+ }
+
+ //The following methods cannot be called from a QueueSession as per JMS spec
+
+ public Topic createTopic(String string) throws JMSException {
+ throw new IllegalStateException("Cannot call createTopic from QueueSession");
+ }
+
+ public TopicSubscriber createDurableSubscriber(Topic topic, String string) throws JMSException {
+ throw new IllegalStateException("Cannot call createDurableSubscriber from QueueSession");
+ }
+
+ public TopicSubscriber createDurableSubscriber(Topic topic, String string, String string1, boolean b) throws JMSException {
+ throw new IllegalStateException("Cannot call createDurableSubscriber from QueueSession");
+ }
+
+ public TemporaryTopic createTemporaryTopic() throws JMSException {
+ throw new IllegalStateException("Cannot call createTemporaryTopic from QueueSession");
+ }
+
+ public void unsubscribe(String string) throws JMSException {
+ throw new IllegalStateException("Cannot call unsubscribe from QueueSession");
+ }
+
+ public AMQSession getSession()
+ {
+ return _session;
+ }
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/client/AMQSession.java b/Final/java/client/src/main/java/org/apache/qpid/client/AMQSession.java
new file mode 100644
index 0000000000..a0b79b135d
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/AMQSession.java
@@ -0,0 +1,2800 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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.AMQInvalidArgumentException;
+import org.apache.qpid.AMQInvalidRoutingKeyException;
+import org.apache.qpid.AMQUndeliveredException;
+import org.apache.qpid.AMQDisconnectedException;
+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.AbstractJMSMessage;
+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.common.AMQPFilterTypes;
+import org.apache.qpid.framing.AMQFrame;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.framing.BasicAckBody;
+import org.apache.qpid.framing.BasicConsumeBody;
+import org.apache.qpid.framing.BasicConsumeOkBody;
+import org.apache.qpid.framing.BasicRecoverBody;
+import org.apache.qpid.framing.BasicRecoverOkBody;
+import org.apache.qpid.framing.BasicRejectBody;
+import org.apache.qpid.framing.ChannelCloseBody;
+import org.apache.qpid.framing.ChannelCloseOkBody;
+import org.apache.qpid.framing.ChannelFlowBody;
+import org.apache.qpid.framing.ChannelFlowOkBody;
+import org.apache.qpid.framing.ExchangeBoundBody;
+import org.apache.qpid.framing.ExchangeBoundOkBody;
+import org.apache.qpid.framing.ExchangeDeclareBody;
+import org.apache.qpid.framing.ExchangeDeclareOkBody;
+import org.apache.qpid.framing.FieldTable;
+import org.apache.qpid.framing.FieldTableFactory;
+import org.apache.qpid.framing.QueueBindBody;
+import org.apache.qpid.framing.QueueBindOkBody;
+import org.apache.qpid.framing.QueueDeclareBody;
+import org.apache.qpid.framing.QueueDeclareOkBody;
+import org.apache.qpid.framing.QueueDeleteBody;
+import org.apache.qpid.framing.QueueDeleteOkBody;
+import org.apache.qpid.framing.TxCommitBody;
+import org.apache.qpid.framing.TxCommitOkBody;
+import org.apache.qpid.framing.TxRollbackBody;
+import org.apache.qpid.framing.TxRollbackOkBody;
+import org.apache.qpid.jms.Session;
+import org.apache.qpid.protocol.AMQConstant;
+import org.apache.qpid.protocol.AMQMethodEvent;
+import org.apache.qpid.url.AMQBindingURL;
+import org.apache.qpid.url.URLSyntaxException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.jms.BytesMessage;
+import javax.jms.Destination;
+import javax.jms.IllegalStateException;
+import javax.jms.InvalidDestinationException;
+import javax.jms.InvalidSelectorException;
+import javax.jms.JMSException;
+import javax.jms.MapMessage;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageListener;
+import javax.jms.MessageProducer;
+import javax.jms.ObjectMessage;
+import javax.jms.Queue;
+import javax.jms.QueueBrowser;
+import javax.jms.QueueReceiver;
+import javax.jms.QueueSender;
+import javax.jms.QueueSession;
+import javax.jms.StreamMessage;
+import javax.jms.TemporaryQueue;
+import javax.jms.TemporaryTopic;
+import javax.jms.TextMessage;
+import javax.jms.Topic;
+import javax.jms.TopicPublisher;
+import javax.jms.TopicSession;
+import javax.jms.TopicSubscriber;
+import java.io.Serializable;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicLong;
+
+/**
+ * <p/><table id="crc"><caption>CRC Card</caption>
+ * <tr><th> Responsibilities <th> Collaborations
+ * <tr><td>
+ * </table>
+ *
+ * @todo Different FailoverSupport implementation are needed on the same method call, in different situations. For
+ * example, when failing-over and reestablishing the bindings, the bind cannot be interrupted by a second
+ * fail-over, if it fails with an exception, the fail-over process should also fail. When binding outside of
+ * the fail-over process, the retry handler could be used to automatically retry the operation once the connection
+ * has been reestablished. All fail-over protected operations should be placed in private methods, with
+ * FailoverSupport passed in by the caller to provide the correct support for the calling context. Sometimes the
+ * fail-over process sets a nowait flag and uses an async method call instead.
+ * @todo Two new objects created on every failover supported method call. Consider more efficient ways of doing this,
+ * after looking at worse bottlenecks first.
+ */
+public class AMQSession extends Closeable implements Session, QueueSession, TopicSession
+{
+ /** Used for debugging. */
+ private static final Logger _logger = LoggerFactory.getLogger(AMQSession.class);
+
+ /** Used for debugging in the dispatcher. */
+ private static final Logger _dispatcherLogger = LoggerFactory.getLogger(Dispatcher.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;
+
+ /**
+ * 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;
+
+ /** System property to enable strict AMQP compliance. */
+ public static final String STRICT_AMQP = "STRICT_AMQP";
+
+ /** Strict AMQP default setting. */
+ public static final String STRICT_AMQP_DEFAULT = "false";
+
+ /** System property to enable failure if strict AMQP compliance is violated. */
+ public static final String STRICT_AMQP_FATAL = "STRICT_AMQP_FATAL";
+
+ /** Strickt AMQP failure default. */
+ public static final String STRICT_AMQP_FATAL_DEFAULT = "true";
+
+ /** System property to enable immediate message prefetching. */
+ public static final String IMMEDIATE_PREFETCH = "IMMEDIATE_PREFETCH";
+
+ /** Immediate message prefetch default. */
+ public static final String IMMEDIATE_PREFETCH_DEFAULT = "false";
+
+ /** The connection to which this session belongs. */
+ private AMQConnection _connection;
+
+ /** Used to indicate whether or not this is a transactional session. */
+ private boolean _transacted;
+
+ /** Holds the sessions acknowledgement mode. */
+ private int _acknowledgeMode;
+
+ /** Holds this session unique identifier, used to distinguish it from other sessions. */
+ private int _channelId;
+
+ /** @todo This does not appear to be set? */
+ private int _ticket;
+
+ /** Holds the high mark for prefetched message, at which the session is suspended. */
+ private int _defaultPrefetchHighMark = DEFAULT_PREFETCH_HIGH_MARK;
+
+ /** Holds the low mark for prefetched messages, below which the session is resumed. */
+ private int _defaultPrefetchLowMark = DEFAULT_PREFETCH_LOW_MARK;
+
+ /** Holds the message listener, if any, which is attached to this session. */
+ private MessageListener _messageListener = null;
+
+ /** Used to indicate that this session has been started at least once. */
+ private AtomicBoolean _startedAtLeastOnce = new AtomicBoolean(false);
+
+ /**
+ * Used to reference durable subscribers so that requests for unsubscribe can be handled correctly. Note this only
+ * keeps a record of subscriptions which have been created in the current instance. It does not remember
+ * subscriptions between executions of the client.
+ */
+ private final ConcurrentHashMap<String, TopicSubscriberAdaptor> _subscriptions =
+ new ConcurrentHashMap<String, TopicSubscriberAdaptor>();
+
+ /**
+ * Holds a mapping from message consumers to their identifying names, so that their subscriptions may be looked
+ * up in the {@link #_subscriptions} map.
+ */
+ private final ConcurrentHashMap<BasicMessageConsumer, String> _reverseSubscriptionMap =
+ new ConcurrentHashMap<BasicMessageConsumer, String>();
+
+ /**
+ * Used to hold incoming messages.
+ *
+ * @todo Weaken the type once {@link FlowControllingBlockingQueue} implements Queue.
+ */
+ private final FlowControllingBlockingQueue _queue;
+
+ /** Holds the highest received delivery tag. */
+ private final AtomicLong _highestDeliveryTag = new AtomicLong(-1);
+
+ /** Holds the dispatcher thread for this session. */
+ private Dispatcher _dispatcher;
+
+ /** Holds the message factory factory for this session. */
+ private MessageFactoryRegistry _messageFactoryRegistry;
+
+ /** Holds all of the producers created by this session, keyed by their unique identifiers. */
+ private Map<Long, MessageProducer> _producers = new ConcurrentHashMap<Long, MessageProducer>();
+
+ /** Used as a source of unique identifiers so that the consumers can be tagged to match them to BasicConsume methods. */
+ private int _nextTag = 1;
+
+ /**
+ * Maps from identifying tags to message consumers, in order to pass dispatch incoming messages to the right
+ * consumer.
+ */
+ private Map<AMQShortString, BasicMessageConsumer> _consumers =
+ new ConcurrentHashMap<AMQShortString, BasicMessageConsumer>();
+
+ /** Provides a count of consumers on destinations, in order to be able to know if a destination has consumers. */
+ private ConcurrentHashMap<Destination, AtomicInteger> _destinationConsumerCount =
+ new ConcurrentHashMap<Destination, AtomicInteger>();
+
+ /**
+ * Used as a source of unique identifiers for producers within the session.
+ *
+ * <p/> Access to this id does not require to be synchronized since according to the JMS specification only one
+ * thread of control is allowed to create producers for any given session instance.
+ */
+ private long _nextProducerId;
+
+ /**
+ * Set when recover is called. This is to handle the case where recover() is called by application code during
+ * onMessage() processing to enure that an auto ack is not sent.
+ */
+ private boolean _inRecovery;
+
+ /** Used to indicates that the connection to which this session belongs, has been stopped. */
+ private boolean _connectionStopped;
+
+ /** Used to indicate that this session has a message listener attached to it. */
+ private boolean _hasMessageListeners;
+
+ /** Used to indicate that this session has been suspended. */
+ private boolean _suspended;
+
+ /**
+ * Used to protect the suspension of this session, so that critical code can be executed during suspension,
+ * without the session being resumed by other threads.
+ */
+ private final Object _suspensionLock = new Object();
+
+ /**
+ * Used to ensure that onlt the first call to start the dispatcher can unsuspend the channel.
+ *
+ * @todo This is accessed only within a synchronized method, so does not need to be atomic.
+ */
+ private final AtomicBoolean _firstDispatcher = new AtomicBoolean(true);
+
+ /** Used to indicate that the session should start pre-fetching messages as soon as it is started. */
+ private final boolean _immediatePrefetch;
+
+ /** Indicates that warnings should be generated on violations of the strict AMQP. */
+ private final boolean _strictAMQP;
+
+ /** Indicates that runtime exceptions should be generated on vilations of the strict AMQP. */
+ private final boolean _strictAMQPFATAL;
+ private final Object _messageDeliveryLock = new Object();
+
+ /**
+ * Creates a new session on a connection.
+ *
+ * @param con The connection on which to create the session.
+ * @param channelId The unique identifier for the session.
+ * @param transacted Indicates whether or not the session is transactional.
+ * @param acknowledgeMode The acknoledgement mode for the session.
+ * @param messageFactoryRegistry The message factory factory for the session.
+ * @param defaultPrefetchHighMark The maximum number of messages to prefetched before suspending the session.
+ * @param defaultPrefetchLowMark The number of prefetched messages at which to resume the session.
+ */
+ AMQSession(AMQConnection con, int channelId, boolean transacted, int acknowledgeMode,
+ MessageFactoryRegistry messageFactoryRegistry, int defaultPrefetchHighMark, int defaultPrefetchLowMark)
+ {
+
+ _strictAMQP = Boolean.parseBoolean(System.getProperties().getProperty(STRICT_AMQP, STRICT_AMQP_DEFAULT));
+ _strictAMQPFATAL =
+ Boolean.parseBoolean(System.getProperties().getProperty(STRICT_AMQP_FATAL, STRICT_AMQP_FATAL_DEFAULT));
+ _immediatePrefetch =
+ _strictAMQP
+ || Boolean.parseBoolean(System.getProperties().getProperty(IMMEDIATE_PREFETCH, IMMEDIATE_PREFETCH_DEFAULT));
+
+ _connection = con;
+ _transacted = transacted;
+ if (transacted)
+ {
+ _acknowledgeMode = javax.jms.Session.SESSION_TRANSACTED;
+ }
+ else
+ {
+ _acknowledgeMode = acknowledgeMode;
+ }
+
+ _channelId = channelId;
+ _messageFactoryRegistry = messageFactoryRegistry;
+ _defaultPrefetchHighMark = defaultPrefetchHighMark;
+ _defaultPrefetchLowMark = defaultPrefetchLowMark;
+
+ if (_acknowledgeMode == NO_ACKNOWLEDGE)
+ {
+ _queue =
+ new FlowControllingBlockingQueue(_defaultPrefetchHighMark, _defaultPrefetchLowMark,
+ new FlowControllingBlockingQueue.ThresholdListener()
+ {
+ public void aboveThreshold(int currentValue)
+ {
+ if (_acknowledgeMode == NO_ACKNOWLEDGE)
+ {
+ _logger.debug(
+ "Above threshold(" + _defaultPrefetchHighMark
+ + ") so suspending channel. Current value is " + currentValue);
+ new Thread(new SuspenderRunner(true)).start();
+ }
+ }
+
+ public void underThreshold(int currentValue)
+ {
+ if (_acknowledgeMode == NO_ACKNOWLEDGE)
+ {
+ _logger.debug(
+ "Below threshold(" + _defaultPrefetchLowMark
+ + ") so unsuspending channel. Current value is " + currentValue);
+ new Thread(new SuspenderRunner(false)).start();
+ }
+ }
+ });
+ }
+ else
+ {
+ _queue = new FlowControllingBlockingQueue(_defaultPrefetchHighMark, null);
+ }
+ }
+
+ /**
+ * Creates a new session on a connection with the default message factory factory.
+ *
+ * @param con The connection on which to create the session.
+ * @param channelId The unique identifier for the session.
+ * @param transacted Indicates whether or not the session is transactional.
+ * @param acknowledgeMode The acknoledgement mode for the session.
+ * @param defaultPrefetchHigh The maximum number of messages to prefetched before suspending the session.
+ * @param defaultPrefetchLow The number of prefetched messages at which to resume the session.
+ */
+ AMQSession(AMQConnection con, int channelId, boolean transacted, int acknowledgeMode, int defaultPrefetchHigh,
+ int defaultPrefetchLow)
+ {
+ this(con, channelId, transacted, acknowledgeMode, MessageFactoryRegistry.newDefaultRegistry(), defaultPrefetchHigh,
+ defaultPrefetchLow);
+ }
+
+ // ===== JMS Session methods.
+
+ /**
+ * Closes the session with no timeout.
+ *
+ * @throws JMSException If the JMS provider fails to close the session due to some internal error.
+ */
+ public void close() throws JMSException
+ {
+ close(-1);
+ }
+
+ public BytesMessage createBytesMessage() throws JMSException
+ {
+ checkNotClosed();
+ return new JMSBytesMessage();
+ }
+
+ /**
+ * Acknowledges all unacknowledged messages on the session, for all message consumers on the session.
+ *
+ * @throws IllegalStateException If the session is closed.
+ */
+ public void acknowledge() throws IllegalStateException
+ {
+ if (isClosed())
+ {
+ throw new IllegalStateException("Session is already closed");
+ }
+
+ for (BasicMessageConsumer consumer : _consumers.values())
+ {
+ consumer.acknowledge();
+ }
+ }
+
+ /**
+ * Acknowledge one or many messages.
+ *
+ * @param deliveryTag The tag of the last message to be acknowledged.
+ * @param multiple <tt>true</tt> to acknowledge all messages up to and including the one specified by the
+ * delivery tag, <tt>false</tt> to just acknowledge that message.
+ *
+ * @todo Be aware of possible changes to parameter order as versions change.
+ */
+ public void acknowledgeMessage(long deliveryTag, boolean multiple)
+ {
+ final AMQFrame ackFrame =
+ BasicAckBody.createAMQFrame(_channelId, getProtocolMajorVersion(), getProtocolMinorVersion(), deliveryTag,
+ multiple);
+
+ if (_logger.isDebugEnabled())
+ {
+ _logger.debug("Sending ack for delivery tag " + deliveryTag + " on channel " + _channelId);
+ }
+
+ getProtocolHandler().writeFrame(ackFrame);
+ }
+
+ /**
+ * Binds the named queue, with the specified routing key, to the named exchange.
+ *
+ * <p/>Note that this operation automatically retries in the event of fail-over.
+ *
+ * @param queueName The name of the queue to bind.
+ * @param routingKey The routing key to bind the queue with.
+ * @param arguments Additional arguments.
+ * @param exchangeName The exchange to bind the queue on.
+ *
+ * @throws AMQException If the queue cannot be bound for any reason.
+ * @todo Be aware of possible changes to parameter order as versions change.
+ * @todo Document the additional arguments that may be passed in the field table. Are these for headers exchanges?
+ */
+ public void bindQueue(final AMQShortString queueName, final AMQShortString routingKey, final FieldTable arguments,
+ final AMQShortString exchangeName) throws AMQException
+ {
+ /*new FailoverRetrySupport<Object, AMQException>(new FailoverProtectedOperation<Object, AMQException>()*/
+ new FailoverNoopSupport<Object, AMQException>(new FailoverProtectedOperation<Object, AMQException>()
+ {
+ public Object execute() throws AMQException, FailoverException
+ {
+ AMQFrame queueBind =
+ QueueBindBody.createAMQFrame(_channelId, getProtocolMajorVersion(), getProtocolMinorVersion(),
+ arguments, // arguments
+ exchangeName, // exchange
+ false, // nowait
+ queueName, // queue
+ routingKey, // routingKey
+ getTicket()); // ticket
+
+ getProtocolHandler().syncWrite(queueBind, QueueBindOkBody.class);
+
+ return null;
+ }
+ }, _connection).execute();
+ }
+
+ /**
+ * Closes the session.
+ *
+ * <p/>Note that this operation succeeds automatically if a fail-over interupts the sycnronous request to close
+ * the channel. This is because the channel is marked as closed before the request to close it is made, so the
+ * fail-over should not re-open it.
+ *
+ * @param timeout The timeout in milliseconds to wait for the session close acknoledgement from the broker.
+ *
+ * @throws JMSException If the JMS provider fails to close the session due to some internal error.
+ * @todo Be aware of possible changes to parameter order as versions change.
+ * @todo Not certain about the logic of ignoring the failover exception, because the channel won't be
+ * re-opened. May need to examine this more carefully.
+ * @todo Note that taking the failover mutex doesn't prevent this operation being interrupted by a failover,
+ * because the failover process sends the failover event before acquiring the mutex itself.
+ */
+ public void close(long timeout) throws JMSException
+ {
+ if (_logger.isInfoEnabled())
+ {
+ StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
+ _logger.info("Closing session: " + this + ":"
+ + Arrays.asList(stackTrace).subList(3, stackTrace.length - 1));
+ }
+
+ synchronized (_connection.getFailoverMutex())
+ {
+ // We must close down all producers and consumers in an orderly fashion. This is the only method
+ // that can be called from a different thread of control from the one controlling the session.
+ synchronized (_messageDeliveryLock)
+ {
+ // Ensure we only try and close an open session.
+ if (!_closed.getAndSet(true))
+ {
+ // we pass null since this is not an error case
+ closeProducersAndConsumers(null);
+
+ try
+ {
+
+ getProtocolHandler().closeSession(this);
+
+ final AMQFrame frame =
+ ChannelCloseBody.createAMQFrame(getChannelId(), getProtocolMajorVersion(), getProtocolMinorVersion(),
+ 0, // classId
+ 0, // methodId
+ AMQConstant.REPLY_SUCCESS.getCode(), // replyCode
+ new AMQShortString("JMS client closing channel")); // replyText
+
+ getProtocolHandler().syncWrite(frame, ChannelCloseOkBody.class, timeout);
+
+ // When control resumes at this point, a reply will have been received that
+ // indicates the broker has closed the channel successfully.
+ }
+ catch (AMQException e)
+ {
+ JMSException jmse = new JMSException("Error closing session: " + e);
+ jmse.setLinkedException(e);
+ throw jmse;
+ }
+ // This is ignored because the channel is already marked as closed so the fail-over process will
+ // not re-open it.
+ catch (FailoverException e)
+ {
+ _logger.debug(
+ "Got FailoverException during channel close, ignored as channel already marked as closed.");
+ }
+ finally
+ {
+ _connection.deregisterSession(_channelId);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Called when the server initiates the closure of the session unilaterally.
+ *
+ * @param e the exception that caused this session to be closed. Null causes the
+ */
+ public void closed(Throwable e) throws JMSException
+ {
+ synchronized (_connection.getFailoverMutex())
+ {
+ if (e instanceof AMQDisconnectedException)
+ {
+ if (_dispatcher != null)
+ {
+ // Failover failed and ain't coming back. Knife the dispatcher.
+ _dispatcher.interrupt();
+ }
+ }
+ 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
+ _closed.set(true);
+ AMQException amqe;
+ if (e instanceof AMQException)
+ {
+ amqe = (AMQException) e;
+ }
+ else
+ {
+ amqe = new AMQException("Closing session forcibly", e);
+ }
+
+ _connection.deregisterSession(_channelId);
+ closeProducersAndConsumers(amqe);
+ }
+ }
+ }
+
+ /**
+ * Commits all messages done in this transaction and releases any locks currently held.
+ *
+ * <p/>If the commit fails, because the commit itself is interrupted by a fail-over between requesting that the
+ * commit be done, and receiving an acknowledgement that it has been done, then a JMSException will be thrown.
+ * The client will be unable to determine whether or not the commit actually happened on the broker in this case.
+ *
+ * @throws JMSException If the JMS provider fails to commit the transaction due to some internal error. This does
+ * not mean that the commit is known to have failed, merely that it is not known whether it
+ * failed or not.
+ * @todo Be aware of possible changes to parameter order as versions change.
+ */
+ public void commit() throws JMSException
+ {
+ checkTransacted();
+
+ try
+ {
+ // Acknowledge up to message last delivered (if any) for each consumer.
+ // need to send ack for messages delivered to consumers so far
+ for (Iterator<BasicMessageConsumer> i = _consumers.values().iterator(); i.hasNext();)
+ {
+ // Sends acknowledgement to server
+ i.next().acknowledgeLastDelivered();
+ }
+
+ // Commits outstanding messages sent and outstanding acknowledgements.
+ final AMQProtocolHandler handler = getProtocolHandler();
+
+ handler.syncWrite(TxCommitBody.createAMQFrame(_channelId, getProtocolMajorVersion(), getProtocolMinorVersion()),
+ TxCommitOkBody.class);
+ }
+ catch (AMQException e)
+ {
+ throw new JMSAMQException("Failed to commit: " + e.getMessage(), e);
+ }
+ catch (FailoverException e)
+ {
+ throw new JMSAMQException("Fail-over interrupted commit. Status of the commit is uncertain.", e);
+ }
+ }
+
+ public void confirmConsumerCancelled(AMQShortString consumerTag)
+ {
+
+ // Remove the consumer from the map
+ BasicMessageConsumer consumer = (BasicMessageConsumer) _consumers.get(consumerTag);
+ if (consumer != null)
+ {
+ // fixme this isn't right.. needs to check if _queue contains data for this consumer
+ if (consumer.isAutoClose()) // && _queue.isEmpty())
+ {
+ consumer.closeWhenNoMessages(true);
+ }
+
+ if (!consumer.isNoConsume())
+ {
+ // Clean the Maps up first
+ // Flush any pending messages for this consumerTag
+ if (_dispatcher != null)
+ {
+ _logger.info("Dispatcher is not null");
+ }
+ else
+ {
+ _logger.info("Dispatcher is null so created stopped dispatcher");
+ startDistpatcherIfNecessary(true);
+ }
+
+ _dispatcher.rejectPending(consumer);
+ }
+ else
+ {
+ // Just close the consumer
+ // fixme the CancelOK is being processed before the arriving messages..
+ // The dispatcher is still to process them so the server sent in order but the client
+ // has yet to receive before the close comes in.
+
+ // consumer.markClosed();
+ }
+ }
+ else
+ {
+ _logger.warn("Unable to confirm cancellation of consumer (" + consumerTag + "). Not found in consumer map.");
+ }
+
+ }
+
+ public QueueBrowser createBrowser(Queue queue) throws JMSException
+ {
+ if (isStrictAMQP())
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ return createBrowser(queue, null);
+ }
+
+ public QueueBrowser createBrowser(Queue queue, String messageSelector) throws JMSException
+ {
+ if (isStrictAMQP())
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ checkNotClosed();
+ checkValidQueue(queue);
+
+ return new AMQQueueBrowser(this, (AMQQueue) queue, messageSelector);
+ }
+
+ public MessageConsumer createBrowserConsumer(Destination destination, String messageSelector, boolean noLocal)
+ throws JMSException
+ {
+ checkValidDestination(destination);
+
+ return createConsumerImpl(destination, _defaultPrefetchHighMark, _defaultPrefetchLowMark, noLocal, false,
+ messageSelector, null, true, true);
+ }
+
+ public MessageConsumer createConsumer(Destination destination) throws JMSException
+ {
+ checkValidDestination(destination);
+
+ return createConsumerImpl(destination, _defaultPrefetchHighMark, _defaultPrefetchLowMark, false, false, null, null,
+ false, false);
+ }
+
+ public MessageConsumer createConsumer(Destination destination, String messageSelector) throws JMSException
+ {
+ checkValidDestination(destination);
+
+ return createConsumerImpl(destination, _defaultPrefetchHighMark, _defaultPrefetchLowMark, false, false,
+ messageSelector, null, false, false);
+ }
+
+ public MessageConsumer createConsumer(Destination destination, String messageSelector, boolean noLocal)
+ throws JMSException
+ {
+ checkValidDestination(destination);
+
+ return createConsumerImpl(destination, _defaultPrefetchHighMark, _defaultPrefetchLowMark, noLocal, false,
+ messageSelector, null, false, false);
+ }
+
+ public MessageConsumer createConsumer(Destination destination, int prefetch, boolean noLocal, boolean exclusive,
+ String selector) throws JMSException
+ {
+ checkValidDestination(destination);
+
+ return createConsumerImpl(destination, prefetch, prefetch, noLocal, exclusive, selector, null, false, false);
+ }
+
+ public MessageConsumer createConsumer(Destination destination, int prefetchHigh, int prefetchLow, boolean noLocal,
+ boolean exclusive, String selector) throws JMSException
+ {
+ checkValidDestination(destination);
+
+ return createConsumerImpl(destination, prefetchHigh, prefetchLow, noLocal, exclusive, selector, null, false, false);
+ }
+
+ public MessageConsumer createConsumer(Destination destination, int prefetch, boolean noLocal, boolean exclusive,
+ String selector, FieldTable rawSelector) throws JMSException
+ {
+ checkValidDestination(destination);
+
+ return createConsumerImpl(destination, prefetch, prefetch, noLocal, exclusive, selector, rawSelector, false, false);
+ }
+
+ public MessageConsumer createConsumer(Destination destination, int prefetchHigh, int prefetchLow, boolean noLocal,
+ boolean exclusive, String selector, FieldTable rawSelector) throws JMSException
+ {
+ checkValidDestination(destination);
+
+ return createConsumerImpl(destination, prefetchHigh, prefetchLow, noLocal, exclusive, selector, rawSelector, false,
+ false);
+ }
+
+ public TopicSubscriber createDurableSubscriber(Topic topic, String name) throws JMSException
+ {
+
+ checkNotClosed();
+ AMQTopic origTopic = checkValidTopic(topic);
+ AMQTopic dest = AMQTopic.createDurableTopic(origTopic, name, _connection);
+ TopicSubscriberAdaptor subscriber = _subscriptions.get(name);
+ if (subscriber != null)
+ {
+ if (subscriber.getTopic().equals(topic))
+ {
+ throw new IllegalStateException("Already subscribed to topic " + topic + " with subscription exchange "
+ + name);
+ }
+ else
+ {
+ unsubscribe(name);
+ }
+ }
+ else
+ {
+ AMQShortString topicName;
+ if (topic instanceof AMQTopic)
+ {
+ topicName = ((AMQTopic) topic).getDestinationName();
+ }
+ else
+ {
+ topicName = new AMQShortString(topic.getTopicName());
+ }
+
+ if (_strictAMQP)
+ {
+ if (_strictAMQPFATAL)
+ {
+ throw new UnsupportedOperationException("JMS Durable not currently supported by AMQP.");
+ }
+ else
+ {
+ _logger.warn("Unable to determine if subscription already exists for '" + topicName + "' "
+ + "for creation durableSubscriber. Requesting queue deletion regardless.");
+ }
+
+ deleteQueue(dest.getAMQQueueName());
+ }
+ else
+ {
+ // if the queue is bound to the exchange but NOT for this topic, then the JMS spec
+ // says we must trash the subscription.
+ if (isQueueBound(dest.getExchangeName(), dest.getAMQQueueName())
+ && !isQueueBound(dest.getExchangeName(), dest.getAMQQueueName(), topicName))
+ {
+ deleteQueue(dest.getAMQQueueName());
+ }
+ }
+ }
+
+ subscriber = new TopicSubscriberAdaptor(dest, (BasicMessageConsumer) createConsumer(dest));
+
+ _subscriptions.put(name, subscriber);
+ _reverseSubscriptionMap.put(subscriber.getMessageConsumer(), name);
+
+ return subscriber;
+ }
+
+ /** Note, currently this does not handle reuse of the same name with different topics correctly. */
+ public TopicSubscriber createDurableSubscriber(Topic topic, String name, String messageSelector, boolean noLocal)
+ throws JMSException
+ {
+ checkNotClosed();
+ checkValidTopic(topic);
+ AMQTopic dest = AMQTopic.createDurableTopic((AMQTopic) topic, name, _connection);
+ BasicMessageConsumer consumer = (BasicMessageConsumer) createConsumer(dest, messageSelector, noLocal);
+ TopicSubscriberAdaptor subscriber = new TopicSubscriberAdaptor(dest, consumer);
+ _subscriptions.put(name, subscriber);
+ _reverseSubscriptionMap.put(subscriber.getMessageConsumer(), name);
+
+ return subscriber;
+ }
+
+ public MapMessage createMapMessage() throws JMSException
+ {
+ checkNotClosed();
+ return new JMSMapMessage();
+ }
+
+ public javax.jms.Message createMessage() throws JMSException
+ {
+ return createBytesMessage();
+ }
+
+ public ObjectMessage createObjectMessage() throws JMSException
+ {
+ checkNotClosed();
+ return (ObjectMessage) new JMSObjectMessage();
+ }
+
+ public ObjectMessage createObjectMessage(Serializable object) throws JMSException
+ {
+ ObjectMessage msg = createObjectMessage();
+ msg.setObject(object);
+
+ return msg;
+ }
+
+ public BasicMessageProducer createProducer(Destination destination) throws JMSException
+ {
+ return createProducerImpl(destination, DEFAULT_MANDATORY, DEFAULT_IMMEDIATE);
+ }
+
+ public BasicMessageProducer createProducer(Destination destination, boolean immediate) throws JMSException
+ {
+ return createProducerImpl(destination, DEFAULT_MANDATORY, immediate);
+ }
+
+ public BasicMessageProducer createProducer(Destination destination, boolean mandatory, boolean immediate)
+ throws JMSException
+ {
+ return createProducerImpl(destination, mandatory, immediate);
+ }
+
+ public BasicMessageProducer createProducer(Destination destination, boolean mandatory, boolean immediate,
+ boolean waitUntilSent) throws JMSException
+ {
+ return createProducerImpl(destination, mandatory, immediate, waitUntilSent);
+ }
+
+ public TopicPublisher createPublisher(Topic topic) throws JMSException
+ {
+ checkNotClosed();
+
+ return new TopicPublisherAdapter((BasicMessageProducer) createProducer(topic), topic);
+ }
+
+ public Queue createQueue(String queueName) throws JMSException
+ {
+ checkNotClosed();
+ if (queueName.indexOf('/') == -1)
+ {
+ return new AMQQueue(getDefaultQueueExchangeName(), new AMQShortString(queueName));
+ }
+ else
+ {
+ try
+ {
+ return new AMQQueue(new AMQBindingURL(queueName));
+ }
+ catch (URLSyntaxException urlse)
+ {
+ JMSException jmse = new JMSException(urlse.getReason());
+ jmse.setLinkedException(urlse);
+
+ throw jmse;
+ }
+ }
+ }
+
+ /**
+ * Declares the named queue.
+ *
+ * <p/>Note that this operation automatically retries in the event of fail-over.
+ *
+ * @param name The name of the queue to declare.
+ * @param autoDelete
+ * @param durable Flag to indicate that the queue is durable.
+ * @param exclusive Flag to indicate that the queue is exclusive to this client.
+ *
+ * @throws AMQException If the queue cannot be declared for any reason.
+ * @todo Be aware of possible changes to parameter order as versions change.
+ */
+ public void createQueue(final AMQShortString name, final boolean autoDelete, final boolean durable,
+ final boolean exclusive) throws AMQException
+ {
+ new FailoverRetrySupport<Object, AMQException>(new FailoverProtectedOperation<Object, AMQException>()
+ {
+ public Object execute() throws AMQException, FailoverException
+ {
+ AMQFrame queueDeclare =
+ QueueDeclareBody.createAMQFrame(_channelId, getProtocolMajorVersion(), getProtocolMinorVersion(),
+ null, // arguments
+ autoDelete, // autoDelete
+ durable, // durable
+ exclusive, // exclusive
+ false, // nowait
+ false, // passive
+ name, // queue
+ getTicket()); // ticket
+
+ getProtocolHandler().syncWrite(queueDeclare, QueueDeclareOkBody.class);
+
+ return null;
+ }
+ }, _connection).execute();
+ }
+
+ /**
+ * Creates a QueueReceiver
+ *
+ * @param destination
+ *
+ * @return QueueReceiver - a wrapper around our MessageConsumer
+ *
+ * @throws JMSException
+ */
+ public QueueReceiver createQueueReceiver(Destination destination) throws JMSException
+ {
+ checkValidDestination(destination);
+ AMQQueue dest = (AMQQueue) destination;
+ BasicMessageConsumer consumer = (BasicMessageConsumer) createConsumer(destination);
+
+ return new QueueReceiverAdaptor(dest, consumer);
+ }
+
+ /**
+ * Creates a QueueReceiver using a message selector
+ *
+ * @param destination
+ * @param messageSelector
+ *
+ * @return QueueReceiver - a wrapper around our MessageConsumer
+ *
+ * @throws JMSException
+ */
+ public QueueReceiver createQueueReceiver(Destination destination, String messageSelector) throws JMSException
+ {
+ checkValidDestination(destination);
+ AMQQueue dest = (AMQQueue) destination;
+ BasicMessageConsumer consumer = (BasicMessageConsumer) createConsumer(destination, messageSelector);
+
+ return new QueueReceiverAdaptor(dest, consumer);
+ }
+
+ /**
+ * Creates a QueueReceiver wrapping a MessageConsumer
+ *
+ * @param queue
+ *
+ * @return QueueReceiver
+ *
+ * @throws JMSException
+ */
+ public QueueReceiver createReceiver(Queue queue) throws JMSException
+ {
+ checkNotClosed();
+ AMQQueue dest = (AMQQueue) queue;
+ BasicMessageConsumer consumer = (BasicMessageConsumer) createConsumer(dest);
+
+ return new QueueReceiverAdaptor(dest, consumer);
+ }
+
+ /**
+ * Creates a QueueReceiver wrapping a MessageConsumer using a message selector
+ *
+ * @param queue
+ * @param messageSelector
+ *
+ * @return QueueReceiver
+ *
+ * @throws JMSException
+ */
+ public QueueReceiver createReceiver(Queue queue, String messageSelector) throws JMSException
+ {
+ checkNotClosed();
+ AMQQueue dest = (AMQQueue) queue;
+ BasicMessageConsumer consumer = (BasicMessageConsumer) createConsumer(dest, messageSelector);
+
+ return new QueueReceiverAdaptor(dest, consumer);
+ }
+
+ public QueueSender createSender(Queue queue) throws JMSException
+ {
+ checkNotClosed();
+
+ // return (QueueSender) createProducer(queue);
+ return new QueueSenderAdapter(createProducer(queue), queue);
+ }
+
+ public StreamMessage createStreamMessage() throws JMSException
+ {
+ synchronized (_connection.getFailoverMutex())
+ {
+ checkNotClosed();
+
+ return new JMSStreamMessage();
+ }
+ }
+
+ /**
+ * Creates a non-durable subscriber
+ *
+ * @param topic
+ *
+ * @return TopicSubscriber - a wrapper round our MessageConsumer
+ *
+ * @throws JMSException
+ */
+ public TopicSubscriber createSubscriber(Topic topic) throws JMSException
+ {
+ checkNotClosed();
+ AMQTopic dest = checkValidTopic(topic);
+
+ // AMQTopic dest = new AMQTopic(topic.getTopicName());
+ return new TopicSubscriberAdaptor(dest, (BasicMessageConsumer) createConsumer(dest));
+ }
+
+ /**
+ * Creates a non-durable subscriber with a message selector
+ *
+ * @param topic
+ * @param messageSelector
+ * @param noLocal
+ *
+ * @return TopicSubscriber - a wrapper round our MessageConsumer
+ *
+ * @throws JMSException
+ */
+ public TopicSubscriber createSubscriber(Topic topic, String messageSelector, boolean noLocal) throws JMSException
+ {
+ checkNotClosed();
+ AMQTopic dest = checkValidTopic(topic);
+
+ // AMQTopic dest = new AMQTopic(topic.getTopicName());
+ return new TopicSubscriberAdaptor(dest, (BasicMessageConsumer) createConsumer(dest, messageSelector, noLocal));
+ }
+
+ public TemporaryQueue createTemporaryQueue() throws JMSException
+ {
+ checkNotClosed();
+
+ return new AMQTemporaryQueue(this);
+ }
+
+ public TemporaryTopic createTemporaryTopic() throws JMSException
+ {
+ checkNotClosed();
+
+ return new AMQTemporaryTopic(this);
+ }
+
+ public TextMessage createTextMessage() throws JMSException
+ {
+ synchronized (_connection.getFailoverMutex())
+ {
+ checkNotClosed();
+
+ return new JMSTextMessage();
+ }
+ }
+
+ public TextMessage createTextMessage(String text) throws JMSException
+ {
+
+ TextMessage msg = createTextMessage();
+ msg.setText(text);
+
+ return msg;
+ }
+
+ public Topic createTopic(String topicName) throws JMSException
+ {
+ checkNotClosed();
+
+ if (topicName.indexOf('/') == -1)
+ {
+ return new AMQTopic(getDefaultTopicExchangeName(), new AMQShortString(topicName));
+ }
+ else
+ {
+ try
+ {
+ return new AMQTopic(new AMQBindingURL(topicName));
+ }
+ catch (URLSyntaxException urlse)
+ {
+ JMSException jmse = new JMSException(urlse.getReason());
+ jmse.setLinkedException(urlse);
+
+ throw jmse;
+ }
+ }
+ }
+
+ public void declareExchange(AMQShortString name, AMQShortString type, boolean nowait) throws AMQException
+ {
+ declareExchange(name, type, getProtocolHandler(), nowait);
+ }
+
+ public int getAcknowledgeMode() throws JMSException
+ {
+ checkNotClosed();
+
+ return _acknowledgeMode;
+ }
+
+ public AMQConnection getAMQConnection()
+ {
+ return _connection;
+ }
+
+ public int getChannelId()
+ {
+ return _channelId;
+ }
+
+ public int getDefaultPrefetch()
+ {
+ return _defaultPrefetchHighMark;
+ }
+
+ public int getDefaultPrefetchHigh()
+ {
+ return _defaultPrefetchHighMark;
+ }
+
+ public int getDefaultPrefetchLow()
+ {
+ return _defaultPrefetchLowMark;
+ }
+
+ public AMQShortString getDefaultQueueExchangeName()
+ {
+ return _connection.getDefaultQueueExchangeName();
+ }
+
+ public AMQShortString getDefaultTopicExchangeName()
+ {
+ return _connection.getDefaultTopicExchangeName();
+ }
+
+ public MessageListener getMessageListener() throws JMSException
+ {
+ // checkNotClosed();
+ return _messageListener;
+ }
+
+ public AMQShortString getTemporaryQueueExchangeName()
+ {
+ return _connection.getTemporaryQueueExchangeName();
+ }
+
+ public AMQShortString getTemporaryTopicExchangeName()
+ {
+ return _connection.getTemporaryTopicExchangeName();
+ }
+
+ public int getTicket()
+ {
+ return _ticket;
+ }
+
+ public boolean getTransacted() throws JMSException
+ {
+ checkNotClosed();
+
+ return _transacted;
+ }
+
+ public boolean hasConsumer(Destination destination)
+ {
+ AtomicInteger counter = _destinationConsumerCount.get(destination);
+
+ return (counter != null) && (counter.get() != 0);
+ }
+
+ public boolean isStrictAMQP()
+ {
+ return _strictAMQP;
+ }
+
+ public boolean isSuspended()
+ {
+ return _suspended;
+ }
+
+ /**
+ * Invoked by the MINA IO thread (indirectly) when a message is received from the transport. Puts the message onto
+ * the queue read by the dispatcher.
+ *
+ * @param message the message that has been received
+ */
+ public void messageReceived(UnprocessedMessage message)
+ {
+ if (_logger.isDebugEnabled())
+ {
+ _logger.debug("Message["
+ + ((message.getDeliverBody() == null) ? ("B:" + message.getBounceBody()) : ("D:" + message.getDeliverBody()))
+ + "] received in session with channel id " + _channelId);
+ }
+
+ if (message.getDeliverBody() == null)
+ {
+ // Return of the bounced message.
+ returnBouncedMessage(message);
+ }
+ else
+ {
+ _highestDeliveryTag.set(message.getDeliverBody().deliveryTag);
+ _queue.add(message);
+ }
+ }
+
+ /**
+ * Stops message delivery in this session, and restarts message delivery with the oldest unacknowledged message.
+ *
+ * <p/>All consumers deliver messages in a serial order. Acknowledging a received message automatically acknowledges all
+ * messages that have been delivered to the client.
+ *
+ * <p/>Restarting a session causes it to take the following actions:
+ *
+ * <ul>
+ * <li>Stop message delivery.</li>
+ * <li>Mark all messages that might have been delivered but not acknowledged as "redelivered".
+ * <li>Restart the delivery sequence including all unacknowledged messages that had been previously delivered.
+ * Redelivered messages do not have to be delivered in exactly their original delivery order.</li>
+ * </ul>
+ *
+ * <p/>If the recover operation is interrupted by a fail-over, between asking that the broker begin recovery and
+ * receiving acknolwedgement that it hasm then a JMSException will be thrown. In this case it will not be possible
+ * for the client to determine whether the broker is going to recover the session or not.
+ *
+ * @throws JMSException If the JMS provider fails to stop and restart message delivery due to some internal error.
+ * Not that this does not necessarily mean that the recovery has failed, but simply that it
+ * is not possible to tell if it has or not.
+ * @todo Be aware of possible changes to parameter order as versions change.
+ */
+ public void recover() throws JMSException
+ {
+ // Ensure that the session is open.
+ checkNotClosed();
+
+ // Ensure that the session is not transacted.
+ checkNotTransacted();
+
+ // this is set only here, and the before the consumer's onMessage is called it is set to false
+ _inRecovery = true;
+ try
+ {
+
+ boolean isSuspended = isSuspended();
+
+ if (!isSuspended)
+ {
+ suspendChannel(true);
+ }
+
+ for (BasicMessageConsumer consumer : _consumers.values())
+ {
+ consumer.clearUnackedMessages();
+ }
+
+ if (_dispatcher != null)
+ {
+ _dispatcher.rollback();
+ }
+
+ if (isStrictAMQP())
+ {
+ // We can't use the BasicRecoverBody-OK method as it isn't part of the spec.
+ _connection.getProtocolHandler().writeFrame(BasicRecoverBody.createAMQFrame(_channelId,
+ getProtocolMajorVersion(), getProtocolMinorVersion(), false)); // requeue
+ _logger.warn("Session Recover cannot be guaranteed with STRICT_AMQP. Messages may arrive out of order.");
+ }
+ else
+ {
+
+ _connection.getProtocolHandler().syncWrite(
+ BasicRecoverBody.createAMQFrame(_channelId, getProtocolMajorVersion(), getProtocolMinorVersion(), false) // requeue
+ , BasicRecoverOkBody.class);
+ }
+
+ if (!isSuspended)
+ {
+ suspendChannel(false);
+ }
+ }
+ catch (AMQException e)
+ {
+ throw new JMSAMQException("Recover failed: " + e.getMessage(), e);
+ }
+ catch (FailoverException e)
+ {
+ throw new JMSAMQException("Recovery was interrupted by fail-over. Recovery status is not known.", e);
+ }
+ }
+
+ public void rejectMessage(UnprocessedMessage message, boolean requeue)
+ {
+
+ if (_logger.isTraceEnabled())
+ {
+ _logger.trace("Rejecting Unacked message:" + message.getDeliverBody().deliveryTag);
+ }
+
+ rejectMessage(message.getDeliverBody().deliveryTag, requeue);
+ }
+
+ public void rejectMessage(AbstractJMSMessage message, boolean requeue)
+ {
+ if (_logger.isTraceEnabled())
+ {
+ _logger.trace("Rejecting Abstract message:" + message.getDeliveryTag());
+ }
+
+ rejectMessage(message.getDeliveryTag(), requeue);
+
+ }
+
+ public void rejectMessage(long deliveryTag, boolean requeue)
+ {
+ if ((_acknowledgeMode == CLIENT_ACKNOWLEDGE) || (_acknowledgeMode == SESSION_TRANSACTED))
+ {
+ if (_logger.isDebugEnabled())
+ {
+ _logger.debug("Rejecting delivery tag:" + deliveryTag + ":SessionHC:" + this.hashCode());
+ }
+
+ AMQFrame basicRejectBody =
+ BasicRejectBody.createAMQFrame(_channelId, getProtocolMajorVersion(), getProtocolMinorVersion(), deliveryTag,
+ requeue);
+
+ _connection.getProtocolHandler().writeFrame(basicRejectBody);
+ }
+ }
+
+ /**
+ * Commits all messages done in this transaction and releases any locks currently held.
+ *
+ * <p/>If the rollback fails, because the rollback itself is interrupted by a fail-over between requesting that the
+ * rollback be done, and receiving an acknowledgement that it has been done, then a JMSException will be thrown.
+ * The client will be unable to determine whether or not the rollback actually happened on the broker in this case.
+ *
+ * @throws JMSException If the JMS provider fails to rollback the transaction due to some internal error. This does
+ * not mean that the rollback is known to have failed, merely that it is not known whether it
+ * failed or not.
+ * @todo Be aware of possible changes to parameter order as versions change.
+ */
+ public void rollback() throws JMSException
+ {
+ synchronized (_suspensionLock)
+ {
+ checkTransacted();
+
+ try
+ {
+ boolean isSuspended = isSuspended();
+
+ if (!isSuspended)
+ {
+ suspendChannel(true);
+ }
+
+ if (_dispatcher != null)
+ {
+ _dispatcher.rollback();
+ }
+
+ _connection.getProtocolHandler().syncWrite(TxRollbackBody.createAMQFrame(_channelId,
+ getProtocolMajorVersion(), getProtocolMinorVersion()), TxRollbackOkBody.class);
+
+ if (!isSuspended)
+ {
+ suspendChannel(false);
+ }
+ }
+ catch (AMQException e)
+ {
+ throw new JMSAMQException("Failed to rollback: " + e, e);
+ }
+ catch (FailoverException e)
+ {
+ throw new JMSAMQException("Fail-over interrupted rollback. Status of the rollback is uncertain.", e);
+ }
+ }
+ }
+
+ public void run()
+ {
+ throw new java.lang.UnsupportedOperationException();
+ }
+
+ public void setMessageListener(MessageListener listener) throws JMSException
+ {
+ // checkNotClosed();
+ //
+ // if (_dispatcher != null && !_dispatcher.connectionStopped())
+ // {
+ // throw new javax.jms.IllegalStateException("Attempt to set listener while session is started.");
+ // }
+ //
+ // // We are stopped
+ // for (Iterator<BasicMessageConsumer> i = _consumers.values().iterator(); i.hasNext();)
+ // {
+ // BasicMessageConsumer consumer = i.next();
+ //
+ // if (consumer.isReceiving())
+ // {
+ // throw new javax.jms.IllegalStateException("Another thread is already receiving synchronously.");
+ // }
+ // }
+ //
+ // _messageListener = listener;
+ //
+ // for (Iterator<BasicMessageConsumer> i = _consumers.values().iterator(); i.hasNext();)
+ // {
+ // i.next().setMessageListener(_messageListener);
+ // }
+
+ }
+
+ /*public void setTicket(int ticket)
+ {
+ _ticket = ticket;
+ }*/
+
+ public void unsubscribe(String name) throws JMSException
+ {
+ checkNotClosed();
+ TopicSubscriberAdaptor subscriber = _subscriptions.get(name);
+ if (subscriber != null)
+ {
+ // send a queue.delete for the subscription
+ deleteQueue(AMQTopic.getDurableTopicQueueName(name, _connection));
+ _subscriptions.remove(name);
+ _reverseSubscriptionMap.remove(subscriber);
+ }
+ else
+ {
+ if (_strictAMQP)
+ {
+ if (_strictAMQPFATAL)
+ {
+ throw new UnsupportedOperationException("JMS Durable not currently supported by AMQP.");
+ }
+ else
+ {
+ _logger.warn("Unable to determine if subscription already exists for '" + name + "' for unsubscribe."
+ + " Requesting queue deletion regardless.");
+ }
+
+ deleteQueue(AMQTopic.getDurableTopicQueueName(name, _connection));
+ }
+ else
+ {
+
+ if (isQueueBound(getDefaultTopicExchangeName(), AMQTopic.getDurableTopicQueueName(name, _connection)))
+ {
+ deleteQueue(AMQTopic.getDurableTopicQueueName(name, _connection));
+ }
+ else
+ {
+ throw new InvalidDestinationException("Unknown subscription exchange:" + name);
+ }
+ }
+ }
+ }
+
+ protected MessageConsumer createConsumerImpl(final Destination destination, final int prefetchHigh,
+ final int prefetchLow, final boolean noLocal, final boolean exclusive, String selector, final FieldTable rawSelector,
+ final boolean noConsume, final boolean autoClose) throws JMSException
+ {
+ checkTemporaryDestination(destination);
+
+ final String messageSelector;
+
+ if (_strictAMQP && !((selector == null) || selector.equals("")))
+ {
+ if (_strictAMQPFATAL)
+ {
+ throw new UnsupportedOperationException("Selectors not currently supported by AMQP.");
+ }
+ else
+ {
+ messageSelector = null;
+ }
+ }
+ else
+ {
+ messageSelector = selector;
+ }
+
+ return new FailoverRetrySupport<MessageConsumer, JMSException>(
+ new FailoverProtectedOperation<MessageConsumer, JMSException>()
+ {
+ public MessageConsumer execute() throws JMSException, FailoverException
+ {
+ checkNotClosed();
+
+ AMQDestination amqd = (AMQDestination) destination;
+
+ final AMQProtocolHandler protocolHandler = getProtocolHandler();
+ // TODO: Define selectors in AMQP
+ // TODO: construct the rawSelector from the selector string if rawSelector == null
+ final FieldTable ft = FieldTableFactory.newFieldTable();
+ // if (rawSelector != null)
+ // ft.put("headers", rawSelector.getDataAsBytes());
+ if (rawSelector != null)
+ {
+ ft.addAll(rawSelector);
+ }
+
+ BasicMessageConsumer consumer =
+ new BasicMessageConsumer(_channelId, _connection, amqd, messageSelector, noLocal,
+ _messageFactoryRegistry, AMQSession.this, protocolHandler, ft, prefetchHigh, prefetchLow,
+ exclusive, _acknowledgeMode, noConsume, autoClose);
+
+ if (_messageListener != null)
+ {
+ consumer.setMessageListener(_messageListener);
+ }
+
+ try
+ {
+ registerConsumer(consumer, false);
+ }
+ catch (AMQInvalidArgumentException ise)
+ {
+ JMSException ex = new InvalidSelectorException(ise.getMessage());
+ ex.setLinkedException(ise);
+ throw ex;
+ }
+ catch (AMQInvalidRoutingKeyException e)
+ {
+ JMSException ide =
+ new InvalidDestinationException("Invalid routing key:" + amqd.getRoutingKey().toString());
+ ide.setLinkedException(e);
+ throw ide;
+ }
+ catch (AMQException e)
+ {
+ JMSException ex = new JMSException("Error registering consumer: " + e);
+
+ if (_logger.isDebugEnabled())
+ {
+ e.printStackTrace();
+ }
+
+ ex.setLinkedException(e);
+ throw ex;
+ }
+
+ synchronized (destination)
+ {
+ _destinationConsumerCount.putIfAbsent(destination, new AtomicInteger());
+ _destinationConsumerCount.get(destination).incrementAndGet();
+ }
+
+ return consumer;
+ }
+ }, _connection).execute();
+ }
+
+ /**
+ * Called by the MessageConsumer when closing, to deregister the consumer from the map from consumerTag to consumer
+ * instance.
+ *
+ * @param consumer the consum
+ */
+ void deregisterConsumer(BasicMessageConsumer consumer)
+ {
+ if (_consumers.remove(consumer.getConsumerTag()) != null)
+ {
+ String subscriptionName = _reverseSubscriptionMap.remove(consumer);
+ if (subscriptionName != null)
+ {
+ _subscriptions.remove(subscriptionName);
+ }
+
+ Destination dest = consumer.getDestination();
+ synchronized (dest)
+ {
+ if (_destinationConsumerCount.get(dest).decrementAndGet() == 0)
+ {
+ _destinationConsumerCount.remove(dest);
+ }
+ }
+ }
+ }
+
+ void deregisterProducer(long producerId)
+ {
+ _producers.remove(new Long(producerId));
+ }
+
+ boolean isInRecovery()
+ {
+ return _inRecovery;
+ }
+
+ boolean isQueueBound(AMQShortString exchangeName, AMQShortString queueName) throws JMSException
+ {
+ return isQueueBound(exchangeName, queueName, null);
+ }
+
+ /**
+ * Tests whether or not the specified queue is bound to the specified exchange under a particular routing key.
+ *
+ * <p/>Note that this operation automatically retries in the event of fail-over.
+ *
+ * @param exchangeName The exchange name to test for binding against.
+ * @param queueName The queue name to check if bound.
+ * @param routingKey The routing key to check if the queue is bound under.
+ *
+ * @return <tt>true</tt> if the queue is bound to the exchange and routing key, <tt>false</tt> if not.
+ *
+ * @throws JMSException If the query fails for any reason.
+ * @todo Be aware of possible changes to parameter order as versions change.
+ */
+ boolean isQueueBound(final AMQShortString exchangeName, final AMQShortString queueName, final AMQShortString routingKey)
+ throws JMSException
+ {
+ try
+ {
+ AMQMethodEvent response =
+ new FailoverRetrySupport<AMQMethodEvent, AMQException>(
+ new FailoverProtectedOperation<AMQMethodEvent, AMQException>()
+ {
+ public AMQMethodEvent execute() throws AMQException, FailoverException
+ {
+ AMQFrame boundFrame =
+ ExchangeBoundBody.createAMQFrame(_channelId, getProtocolMajorVersion(),
+ getProtocolMinorVersion(), exchangeName, // exchange
+ queueName, // queue
+ routingKey); // routingKey
+
+ return getProtocolHandler().syncWrite(boundFrame, ExchangeBoundOkBody.class);
+
+ }
+ }, _connection).execute();
+
+ // Extract and return the response code from the query.
+ ExchangeBoundOkBody responseBody = (ExchangeBoundOkBody) response.getMethod();
+
+ return (responseBody.replyCode == 0);
+ }
+ catch (AMQException e)
+ {
+ throw new JMSAMQException("Queue bound query failed: " + e.getMessage(), e);
+ }
+ }
+
+ /**
+ * Called to mark the session as being closed. Useful when the session needs to be made invalid, e.g. after failover
+ * when the client has veoted resubscription. <p/> The caller of this method must already hold the failover mutex.
+ */
+ void markClosed()
+ {
+ _closed.set(true);
+ _connection.deregisterSession(_channelId);
+ markClosedProducersAndConsumers();
+
+ }
+
+ /**
+ * Resubscribes all producers and consumers. This is called when performing failover.
+ *
+ * @throws AMQException
+ */
+ void resubscribe() throws AMQException
+ {
+ resubscribeProducers();
+ resubscribeConsumers();
+ }
+
+ void setHasMessageListeners()
+ {
+ _hasMessageListeners = true;
+ }
+
+ void setInRecovery(boolean inRecovery)
+ {
+ _inRecovery = inRecovery;
+ }
+
+ /**
+ * Starts the session, which ensures that it is not suspended and that its event dispatcher is running.
+ *
+ * @throws AMQException If the session cannot be started for any reason.
+ * @todo This should be controlled by _stopped as it pairs with the stop method fixme or check the
+ * FlowControlledBlockingQueue _queue to see if we have flow controlled. will result in sending Flow messages
+ * for each subsequent call to flow.. only need to do this if we have called stop.
+ */
+ void start() throws AMQException
+ {
+ // Check if the session has perviously been started and suspended, in which case it must be unsuspended.
+ if (_startedAtLeastOnce.getAndSet(true))
+ {
+ suspendChannel(false);
+ }
+
+ // If the event dispatcher is not running then start it too.
+ if (hasMessageListeners())
+ {
+ startDistpatcherIfNecessary();
+ }
+ }
+
+ void startDistpatcherIfNecessary()
+ {
+ //If we are the dispatcher then we don't need to check we are started
+ if (Thread.currentThread() == _dispatcher)
+ {
+ return;
+ }
+
+ // If IMMEDIATE_PREFETCH is not set then we need to start fetching
+ // This is final per session so will be multi-thread safe.
+ if (!_immediatePrefetch)
+ {
+ // We do this now if this is the first call on a started connection
+ if (isSuspended() && _startedAtLeastOnce.get() && _firstDispatcher.getAndSet(false))
+ {
+ try
+ {
+ suspendChannel(false);
+ }
+ catch (AMQException e)
+ {
+ _logger.info("Unsuspending channel threw an exception:" + e);
+ }
+ }
+ }
+
+ startDistpatcherIfNecessary(false);
+ }
+
+ synchronized void startDistpatcherIfNecessary(boolean initiallyStopped)
+ {
+ if (_dispatcher == null)
+ {
+ _dispatcher = new Dispatcher();
+ _dispatcher.setDaemon(true);
+ _dispatcher.setConnectionStopped(initiallyStopped);
+ _dispatcher.start();
+ }
+ else
+ {
+ _dispatcher.setConnectionStopped(initiallyStopped);
+ }
+ }
+
+ void stop() throws AMQException
+ {
+ // Stop the server delivering messages to this session.
+ suspendChannel(true);
+
+ if (_dispatcher != null)
+ {
+ _dispatcher.setConnectionStopped(true);
+ }
+ }
+
+ /*
+ * Binds the named queue, with the specified routing key, to the named exchange.
+ *
+ * <p/>Note that this operation automatically retries in the event of fail-over.
+ *
+ * @param queueName The name of the queue to bind.
+ * @param routingKey The routing key to bind the queue with.
+ * @param arguments Additional arguments.
+ * @param exchangeName The exchange to bind the queue on.
+ *
+ * @throws AMQException If the queue cannot be bound for any reason.
+ */
+ /*private void bindQueue(AMQDestination amqd, AMQShortString queueName, AMQProtocolHandler protocolHandler, FieldTable ft)
+ throws AMQException, FailoverException
+ {
+ AMQFrame queueBind =
+ QueueBindBody.createAMQFrame(_channelId, getProtocolMajorVersion(), getProtocolMinorVersion(), ft, // arguments
+ amqd.getExchangeName(), // exchange
+ false, // nowait
+ queueName, // queue
+ amqd.getRoutingKey(), // routingKey
+ getTicket()); // ticket
+
+ protocolHandler.syncWrite(queueBind, QueueBindOkBody.class);
+ }*/
+
+ private void checkNotTransacted() throws JMSException
+ {
+ if (getTransacted())
+ {
+ throw new IllegalStateException("Session is transacted");
+ }
+ }
+
+ private void checkTemporaryDestination(Destination destination) throws JMSException
+ {
+ if ((destination instanceof TemporaryDestination))
+ {
+ _logger.debug("destination is temporary");
+ final TemporaryDestination tempDest = (TemporaryDestination) destination;
+ if (tempDest.getSession() != this)
+ {
+ _logger.debug("destination is on different session");
+ throw new JMSException("Cannot consume from a temporary destination created onanother session");
+ }
+
+ if (tempDest.isDeleted())
+ {
+ _logger.debug("destination is deleted");
+ throw new JMSException("Cannot consume from a deleted destination");
+ }
+ }
+ }
+
+ private void checkTransacted() throws JMSException
+ {
+ if (!getTransacted())
+ {
+ throw new IllegalStateException("Session is not transacted");
+ }
+ }
+
+ private void checkValidDestination(Destination destination) throws InvalidDestinationException
+ {
+ if (destination == null)
+ {
+ throw new javax.jms.InvalidDestinationException("Invalid Queue");
+ }
+ }
+
+ private void checkValidQueue(Queue queue) throws InvalidDestinationException
+ {
+ if (queue == null)
+ {
+ throw new javax.jms.InvalidDestinationException("Invalid Queue");
+ }
+ }
+
+ /*
+ * I could have combined the last 3 methods, but this way it improves readability
+ */
+ private AMQTopic checkValidTopic(Topic topic) throws JMSException
+ {
+ if (topic == null)
+ {
+ throw new javax.jms.InvalidDestinationException("Invalid Topic");
+ }
+
+ if ((topic instanceof TemporaryDestination) && (((TemporaryDestination) topic).getSession() != this))
+ {
+ throw new javax.jms.InvalidDestinationException(
+ "Cannot create a subscription on a temporary topic created in another session");
+ }
+
+ if (!(topic instanceof AMQTopic))
+ {
+ throw new javax.jms.InvalidDestinationException(
+ "Cannot create a subscription on topic created for another JMS Provider, class of topic provided is: "
+ + topic.getClass().getName());
+ }
+
+ return (AMQTopic) topic;
+ }
+
+ /**
+ * Called to close message consumers cleanly. This may or may <b>not</b> be as a result of an error.
+ *
+ * @param error not null if this is a result of an error occurring at the connection level
+ */
+ private void closeConsumers(Throwable error) throws JMSException
+ {
+ // we need to clone the list of consumers since the close() method updates the _consumers collection
+ // which would result in a concurrent modification exception
+ final ArrayList<BasicMessageConsumer> clonedConsumers = new ArrayList<BasicMessageConsumer>(_consumers.values());
+
+ final Iterator<BasicMessageConsumer> it = clonedConsumers.iterator();
+ while (it.hasNext())
+ {
+ final BasicMessageConsumer con = it.next();
+ if (error != null)
+ {
+ con.notifyError(error);
+ }
+ else
+ {
+ con.close(false);
+ }
+ }
+ // at this point the _consumers map will be empty
+ if (_dispatcher != null)
+ {
+ _dispatcher.close();
+ _dispatcher = null;
+ }
+ }
+
+ /**
+ * Called to close message producers cleanly. This may or may <b>not</b> be as a result of an error. There is
+ * currently no way of propagating errors to message producers (this is a JMS limitation).
+ */
+ private void closeProducers() throws JMSException
+ {
+ // we need to clone the list of producers since the close() method updates the _producers collection
+ // which would result in a concurrent modification exception
+ final ArrayList clonedProducers = new ArrayList(_producers.values());
+
+ final Iterator it = clonedProducers.iterator();
+ while (it.hasNext())
+ {
+ final BasicMessageProducer prod = (BasicMessageProducer) it.next();
+ prod.close();
+ }
+ // at this point the _producers map is empty
+ }
+
+ /**
+ * Close all producers or consumers. This is called either in the error case or when closing the session normally.
+ *
+ * @param amqe the exception, may be null to indicate no error has occurred
+ */
+ private void closeProducersAndConsumers(AMQException amqe) throws JMSException
+ {
+ JMSException jmse = null;
+ try
+ {
+ closeProducers();
+ }
+ catch (JMSException e)
+ {
+ _logger.error("Error closing session: " + e, e);
+ jmse = e;
+ }
+
+ try
+ {
+ closeConsumers(amqe);
+ }
+ catch (JMSException e)
+ {
+ _logger.error("Error closing session: " + e, e);
+ if (jmse == null)
+ {
+ jmse = e;
+ }
+ }
+
+ if (jmse != null)
+ {
+ throw jmse;
+ }
+ }
+
+ /**
+ * Register to consume from the queue.
+ *
+ * @param queueName
+ */
+ private void consumeFromQueue(BasicMessageConsumer consumer, AMQShortString queueName,
+ AMQProtocolHandler protocolHandler, boolean nowait, String messageSelector) throws AMQException, FailoverException
+ {
+ // need to generate a consumer tag on the client so we can exploit the nowait flag
+ AMQShortString tag = new AMQShortString(Integer.toString(_nextTag++));
+
+ FieldTable arguments = FieldTableFactory.newFieldTable();
+ if ((messageSelector != null) && !messageSelector.equals(""))
+ {
+ arguments.put(AMQPFilterTypes.JMS_SELECTOR.getValue(), messageSelector);
+ }
+
+ if (consumer.isAutoClose())
+ {
+ arguments.put(AMQPFilterTypes.AUTO_CLOSE.getValue(), Boolean.TRUE);
+ }
+
+ if (consumer.isNoConsume())
+ {
+ arguments.put(AMQPFilterTypes.NO_CONSUME.getValue(), Boolean.TRUE);
+ }
+
+ consumer.setConsumerTag(tag);
+ // we must register the consumer in the map before we actually start listening
+ _consumers.put(tag, consumer);
+
+ try
+ {
+ // TODO: Be aware of possible changes to parameter order as versions change.
+ AMQFrame jmsConsume =
+ BasicConsumeBody.createAMQFrame(_channelId, getProtocolMajorVersion(), getProtocolMinorVersion(), arguments, // arguments
+ tag, // consumerTag
+ consumer.isExclusive(), // exclusive
+ consumer.getAcknowledgeMode() == Session.NO_ACKNOWLEDGE, // noAck
+ consumer.isNoLocal(), // noLocal
+ nowait, // nowait
+ queueName, // queue
+ getTicket()); // ticket
+
+ if (nowait)
+ {
+ protocolHandler.writeFrame(jmsConsume);
+ }
+ else
+ {
+ protocolHandler.syncWrite(jmsConsume, BasicConsumeOkBody.class);
+ }
+ }
+ catch (AMQException e)
+ {
+ // clean-up the map in the event of an error
+ _consumers.remove(tag);
+ throw e;
+ }
+ }
+
+ private BasicMessageProducer createProducerImpl(Destination destination, boolean mandatory, boolean immediate)
+ throws JMSException
+ {
+ return createProducerImpl(destination, mandatory, immediate, false);
+ }
+
+ private BasicMessageProducer createProducerImpl(final Destination destination, final boolean mandatory,
+ final boolean immediate, final boolean waitUntilSent) throws JMSException
+ {
+ return new FailoverRetrySupport<BasicMessageProducer, JMSException>(
+ new FailoverProtectedOperation<BasicMessageProducer, JMSException>()
+ {
+ public BasicMessageProducer execute() throws JMSException, FailoverException
+ {
+ checkNotClosed();
+ long producerId = getNextProducerId();
+ BasicMessageProducer producer =
+ new BasicMessageProducer(_connection, (AMQDestination) destination, _transacted, _channelId,
+ AMQSession.this, getProtocolHandler(), producerId, immediate, mandatory, waitUntilSent);
+ registerProducer(producerId, producer);
+
+ return producer;
+ }
+ }, _connection).execute();
+ }
+
+ private void declareExchange(AMQDestination amqd, AMQProtocolHandler protocolHandler, boolean nowait) throws AMQException
+ {
+ declareExchange(amqd.getExchangeName(), amqd.getExchangeClass(), protocolHandler, nowait);
+ }
+
+ /**
+ * Declares the named exchange and type of exchange.
+ *
+ * <p/>Note that this operation automatically retries in the event of fail-over.
+ *
+ * @param name The name of the exchange to declare.
+ * @param type The type of the exchange to declare.
+ * @param protocolHandler The protocol handler to process the communication through.
+ * @param nowait
+ *
+ * @throws AMQException If the exchange cannot be declared for any reason.
+ * @todo Be aware of possible changes to parameter order as versions change.
+ */
+ private void declareExchange(final AMQShortString name, final AMQShortString type,
+ final AMQProtocolHandler protocolHandler, final boolean nowait) throws AMQException
+ {
+ new FailoverNoopSupport<Object, AMQException>(new FailoverProtectedOperation<Object, AMQException>()
+ {
+ public Object execute() throws AMQException, FailoverException
+ {
+ AMQFrame exchangeDeclare =
+ ExchangeDeclareBody.createAMQFrame(_channelId, getProtocolMajorVersion(), getProtocolMinorVersion(),
+ null, // arguments
+ false, // autoDelete
+ false, // durable
+ name, // exchange
+ false, // internal
+ nowait, // nowait
+ false, // passive
+ getTicket(), // ticket
+ type); // type
+
+ protocolHandler.syncWrite(exchangeDeclare, ExchangeDeclareOkBody.class);
+
+ return null;
+ }
+ }, _connection).execute();
+ }
+
+ /**
+ * Declares a queue for a JMS destination.
+ *
+ * <p/>Note that for queues but not topics the name is generated in the client rather than the server. This allows
+ * the name to be reused on failover if required. In general, the destination indicates whether it wants a name
+ * generated or not.
+ *
+ * <p/>Note that this operation automatically retries in the event of fail-over.
+ *
+ * @param amqd The destination to declare as a queue.
+ * @param protocolHandler The protocol handler to communicate through.
+ *
+ * @return The name of the decalred queue. This is useful where the broker is generating a queue name on behalf of
+ * the client.
+ *
+ * @throws AMQException If the queue cannot be declared for any reason.
+ * @todo Verify the destiation is valid or throw an exception.
+ * @todo Be aware of possible changes to parameter order as versions change.
+ */
+ private AMQShortString declareQueue(final AMQDestination amqd, final AMQProtocolHandler protocolHandler)
+ throws AMQException
+ {
+ /*return new FailoverRetrySupport<AMQShortString, AMQException>(*/
+ return new FailoverNoopSupport<AMQShortString, AMQException>(
+ new FailoverProtectedOperation<AMQShortString, AMQException>()
+ {
+ public AMQShortString execute() throws AMQException, FailoverException
+ {
+ // Generate the queue name if the destination indicates that a client generated name is to be used.
+ if (amqd.isNameRequired())
+ {
+ amqd.setQueueName(protocolHandler.generateQueueName());
+ }
+
+ AMQFrame queueDeclare =
+ QueueDeclareBody.createAMQFrame(_channelId, getProtocolMajorVersion(), getProtocolMinorVersion(),
+ null, // arguments
+ amqd.isAutoDelete(), // autoDelete
+ amqd.isDurable(), // durable
+ amqd.isExclusive(), // exclusive
+ false, // nowait
+ false, // passive
+ amqd.getAMQQueueName(), // queue
+ getTicket()); // ticket
+
+ protocolHandler.syncWrite(queueDeclare, QueueDeclareOkBody.class);
+
+ return amqd.getAMQQueueName();
+ }
+ }, _connection).execute();
+ }
+
+ /**
+ * Undeclares the specified queue.
+ *
+ * <p/>Note that this operation automatically retries in the event of fail-over.
+ *
+ * @param queueName The name of the queue to delete.
+ *
+ * @throws JMSException If the queue could not be deleted for any reason.
+ * @todo Be aware of possible changes to parameter order as versions change.
+ */
+ private void deleteQueue(final AMQShortString queueName) throws JMSException
+ {
+ try
+ {
+ new FailoverRetrySupport<Object, AMQException>(new FailoverProtectedOperation<Object, AMQException>()
+ {
+ public Object execute() throws AMQException, FailoverException
+ {
+ AMQFrame queueDeleteFrame =
+ QueueDeleteBody.createAMQFrame(_channelId, getProtocolMajorVersion(), getProtocolMinorVersion(),
+ false, // ifEmpty
+ false, // ifUnused
+ true, // nowait
+ queueName, // queue
+ getTicket()); // ticket
+
+ getProtocolHandler().syncWrite(queueDeleteFrame, QueueDeleteOkBody.class);
+
+ return null;
+ }
+ }, _connection).execute();
+ }
+ catch (AMQException e)
+ {
+ throw new JMSAMQException("The queue deletion failed: " + e.getMessage(), e);
+ }
+ }
+
+ private long getNextProducerId()
+ {
+ return ++_nextProducerId;
+ }
+
+ private AMQProtocolHandler getProtocolHandler()
+ {
+ return _connection.getProtocolHandler();
+ }
+
+ private byte getProtocolMajorVersion()
+ {
+ return getProtocolHandler().getProtocolMajorVersion();
+ }
+
+ private byte getProtocolMinorVersion()
+ {
+ return getProtocolHandler().getProtocolMinorVersion();
+ }
+
+ private boolean hasMessageListeners()
+ {
+ return _hasMessageListeners;
+ }
+
+ private void markClosedConsumers() throws JMSException
+ {
+ if (_dispatcher != null)
+ {
+ _dispatcher.close();
+ _dispatcher = null;
+ }
+ // we need to clone the list of consumers since the close() method updates the _consumers collection
+ // which would result in a concurrent modification exception
+ final ArrayList<BasicMessageConsumer> clonedConsumers = new ArrayList<BasicMessageConsumer>(_consumers.values());
+
+ final Iterator<BasicMessageConsumer> it = clonedConsumers.iterator();
+ while (it.hasNext())
+ {
+ final BasicMessageConsumer con = it.next();
+ con.markClosed();
+ }
+ // at this point the _consumers map will be empty
+ }
+
+ private void markClosedProducersAndConsumers()
+ {
+ try
+ {
+ // no need for a markClosed* method in this case since there is no protocol traffic closing a producer
+ closeProducers();
+ }
+ catch (JMSException e)
+ {
+ _logger.error("Error closing session: " + e, e);
+ }
+
+ try
+ {
+ markClosedConsumers();
+ }
+ catch (JMSException e)
+ {
+ _logger.error("Error closing session: " + e, e);
+ }
+ }
+
+ public void declareAndBind(AMQDestination amqd)
+ throws
+ AMQException
+ {
+ AMQProtocolHandler protocolHandler = getProtocolHandler();
+ declareExchange(amqd, protocolHandler, false);
+ AMQShortString queueName = declareQueue(amqd, protocolHandler);
+ bindQueue(queueName, amqd.getRoutingKey(), new FieldTable(), amqd.getExchangeName());
+ }
+
+ /**
+ * Callers must hold the failover mutex before calling this method.
+ *
+ * @param consumer
+ *
+ * @throws AMQException
+ */
+ private void registerConsumer(BasicMessageConsumer consumer, boolean nowait) throws AMQException // , FailoverException
+ {
+ AMQDestination amqd = consumer.getDestination();
+
+ AMQProtocolHandler protocolHandler = getProtocolHandler();
+
+ declareExchange(amqd, protocolHandler, false);
+
+ AMQShortString queueName = declareQueue(amqd, protocolHandler);
+
+ // bindQueue(amqd, queueName, protocolHandler, consumer.getRawSelectorFieldTable());
+ bindQueue(queueName, amqd.getRoutingKey(), consumer.getRawSelectorFieldTable(), amqd.getExchangeName());
+
+ // If IMMEDIATE_PREFETCH is not required then suspsend the channel to delay prefetch
+ if (!_immediatePrefetch)
+ {
+ // The dispatcher will be null if we have just created this session
+ // so suspend the channel before we register our consumer so that we don't
+ // start prefetching until a receive/mListener is set.
+ if (_dispatcher == null)
+ {
+ if (!isSuspended())
+ {
+ try
+ {
+ suspendChannel(true);
+ _logger.info(
+ "Prefetching delayed existing messages will not flow until requested via receive*() or setML().");
+ }
+ catch (AMQException e)
+ {
+ _logger.info("Suspending channel threw an exception:" + e);
+ }
+ }
+ }
+ }
+ else
+ {
+ _logger.info("Immediately prefetching existing messages to new consumer.");
+ }
+
+ try
+ {
+ consumeFromQueue(consumer, queueName, protocolHandler, nowait, consumer.getMessageSelector());
+ }
+ catch (JMSException e) // thrown by getMessageSelector
+ {
+ throw new AMQException(e.getMessage(), e);
+ }
+ catch (FailoverException e)
+ {
+ throw new AMQException("Fail-over exception interrupted basic consume.", e);
+ }
+ }
+
+ private void registerProducer(long producerId, MessageProducer producer)
+ {
+ _producers.put(new Long(producerId), producer);
+ }
+
+ /**
+ * @param consumerTag The consumerTag to prune from queue or all if null
+ * @param requeue Should the removed messages be requeued (or discarded. Possibly to DLQ)
+ */
+
+ private void rejectMessagesForConsumerTag(AMQShortString consumerTag, boolean requeue)
+ {
+ Iterator messages = _queue.iterator();
+ if (_logger.isInfoEnabled())
+ {
+ _logger.info("Rejecting messages from _queue for Consumer tag(" + consumerTag + ") (PDispatchQ) requeue:"
+ + requeue);
+
+ if (messages.hasNext())
+ {
+ _logger.info("Checking all messages in _queue for Consumer tag(" + consumerTag + ")");
+ }
+ else
+ {
+ _logger.info("No messages in _queue to reject");
+ }
+ }
+ while (messages.hasNext())
+ {
+ UnprocessedMessage message = (UnprocessedMessage) messages.next();
+
+ if ((consumerTag == null) || message.getDeliverBody().consumerTag.equals(consumerTag))
+ {
+ if (_logger.isDebugEnabled())
+ {
+ _logger.debug("Removing message(" + System.identityHashCode(message) + ") from _queue DT:"
+ + message.getDeliverBody().deliveryTag);
+ }
+
+ messages.remove();
+
+ rejectMessage(message, requeue);
+
+ if (_logger.isDebugEnabled())
+ {
+ _logger.debug("Rejected the message(" + message.getDeliverBody() + ") for consumer :" + consumerTag);
+ }
+ }
+ }
+ }
+
+ private void resubscribeConsumers() throws AMQException
+ {
+ ArrayList consumers = new ArrayList(_consumers.values());
+ _consumers.clear();
+
+ for (Iterator it = consumers.iterator(); it.hasNext();)
+ {
+ BasicMessageConsumer consumer = (BasicMessageConsumer) it.next();
+ registerConsumer(consumer, true);
+ }
+ }
+
+ private void resubscribeProducers() throws AMQException
+ {
+ ArrayList producers = new ArrayList(_producers.values());
+ _logger.info(MessageFormat.format("Resubscribing producers = {0} producers.size={1}", producers, producers.size())); // FIXME: removeKey
+ for (Iterator it = producers.iterator(); it.hasNext();)
+ {
+ BasicMessageProducer producer = (BasicMessageProducer) it.next();
+ producer.resubscribe();
+ }
+ }
+
+ private void returnBouncedMessage(final UnprocessedMessage message)
+ {
+ _connection.performConnectionTask(new Runnable()
+ {
+ public void run()
+ {
+ try
+ {
+ // Bounced message is processed here, away from the mina thread
+ AbstractJMSMessage bouncedMessage =
+ _messageFactoryRegistry.createMessage(0, false, message.getBounceBody().exchange,
+ message.getBounceBody().routingKey, message.getContentHeader(), message.getBodies());
+
+ AMQConstant errorCode = AMQConstant.getConstant(message.getBounceBody().replyCode);
+ AMQShortString reason = message.getBounceBody().replyText;
+ _logger.debug("Message returned with error code " + errorCode + " (" + reason + ")");
+
+ // @TODO should this be moved to an exception handler of sorts. Somewhere errors are converted to correct execeptions.
+ if (errorCode == AMQConstant.NO_CONSUMERS)
+ {
+ _connection.exceptionReceived(new AMQNoConsumersException("Error: " + reason, bouncedMessage));
+ }
+ else if (errorCode == AMQConstant.NO_ROUTE)
+ {
+ _connection.exceptionReceived(new AMQNoRouteException("Error: " + reason, bouncedMessage));
+ }
+ else
+ {
+ _connection.exceptionReceived(
+ new AMQUndeliveredException(errorCode, "Error: " + reason, bouncedMessage));
+ }
+
+ }
+ catch (Exception e)
+ {
+ _logger.error(
+ "Caught exception trying to raise undelivered message exception (dump follows) - ignoring...",
+ e);
+ }
+ }
+ });
+ }
+
+ /**
+ * Suspends or unsuspends this session.
+ *
+ * @param suspend <tt>true</tt> indicates that the session should be suspended, <tt>false<tt> indicates that it
+ * should be unsuspended.
+ *
+ * @throws AMQException If the session cannot be suspended for any reason.
+ * @todo Be aware of possible changes to parameter order as versions change.
+ */
+ private void suspendChannel(boolean suspend) throws AMQException // , FailoverException
+ {
+ synchronized (_suspensionLock)
+ {
+ try
+ {
+ if (_logger.isDebugEnabled())
+ {
+ _logger.debug("Setting channel flow : " + (suspend ? "suspended" : "unsuspended"));
+ }
+
+ _suspended = suspend;
+
+ AMQFrame channelFlowFrame =
+ ChannelFlowBody.createAMQFrame(_channelId, getProtocolMajorVersion(), getProtocolMinorVersion(),
+ !suspend);
+
+ _connection.getProtocolHandler().syncWrite(channelFlowFrame, ChannelFlowOkBody.class);
+ }
+ catch (FailoverException e)
+ {
+ throw new AMQException("Fail-over interrupted suspend/unsuspend channel.", e);
+ }
+ }
+ }
+
+ Object getMessageDeliveryLock()
+ {
+ return _messageDeliveryLock;
+ }
+
+ /** Responsible for decoding a message fragment and passing it to the appropriate message consumer. */
+ private class Dispatcher extends Thread
+ {
+
+ /** Track the 'stopped' state of the dispatcher, a session starts in the stopped state. */
+ private final AtomicBoolean _dispatcherClosed = 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()
+ {
+ _dispatcherClosed.set(true);
+ interrupt();
+
+ // fixme awaitTermination
+
+ }
+
+ public void rejectPending(BasicMessageConsumer consumer)
+ {
+ synchronized (_lock)
+ {
+ boolean stopped = _dispatcher.connectionStopped();
+
+ if (!stopped)
+ {
+ _dispatcher.setConnectionStopped(true);
+ }
+
+ // Reject messages on pre-receive queue
+ consumer.rollback();
+
+ // Reject messages on pre-dispatch queue
+ rejectMessagesForConsumerTag(consumer.getConsumerTag(), true);
+ //Let the dispatcher deal with this when it gets to them.
+
+ // closeConsumer
+ consumer.markClosed();
+
+ _dispatcher.setConnectionStopped(stopped);
+
+ }
+ }
+
+ public void rollback()
+ {
+
+ synchronized (_lock)
+ {
+ boolean isStopped = connectionStopped();
+
+ if (!isStopped)
+ {
+ setConnectionStopped(true);
+ }
+
+ _rollbackMark.set(_highestDeliveryTag.get());
+
+ _dispatcherLogger.debug("Session Pre Dispatch Queue cleared");
+
+ for (BasicMessageConsumer consumer : _consumers.values())
+ {
+ if (!consumer.isNoConsume())
+ {
+ consumer.rollback();
+ }
+ else
+ {
+ // cClear the _SQ here.
+ consumer.clearReceiveQueue();
+ }
+
+ }
+
+ setConnectionStopped(isStopped);
+ }
+
+ }
+
+ public void run()
+ {
+ if (_dispatcherLogger.isInfoEnabled())
+ {
+ _dispatcherLogger.info(getName() + " started");
+ }
+
+ UnprocessedMessage message;
+
+ // Allow disptacher to start stopped
+ synchronized (_lock)
+ {
+ while (!_closed.get() && connectionStopped())
+ {
+ try
+ {
+ _lock.wait(2000);
+ }
+ catch (InterruptedException e)
+ {
+ // ignore
+ }
+ }
+ }
+
+ try
+ {
+ while (!_dispatcherClosed.get())
+ {
+ message = (UnprocessedMessage) _queue.poll(1000, TimeUnit.MILLISECONDS);
+ if (message != null)
+ {
+ synchronized (_lock)
+ {
+
+ while (connectionStopped())
+ {
+ _lock.wait(2000);
+ }
+
+ if (message.getDeliverBody().deliveryTag <= _rollbackMark.get())
+ {
+ rejectMessage(message, true);
+ }
+ else
+ {
+ synchronized (_messageDeliveryLock)
+ {
+ dispatchMessage(message);
+ }
+ }
+
+ }
+ }
+ }
+ }
+ catch (InterruptedException e)
+ {
+ // ignore
+ }
+
+ if (_dispatcherLogger.isInfoEnabled())
+ {
+ _dispatcherLogger.info(getName() + " thread terminating for channel " + _channelId);
+ }
+ }
+
+ // only call while holding lock
+ final boolean connectionStopped()
+ {
+ return _connectionStopped;
+ }
+
+ boolean setConnectionStopped(boolean connectionStopped)
+ {
+ boolean currently;
+ synchronized (_lock)
+ {
+ currently = _connectionStopped;
+ _connectionStopped = connectionStopped;
+ _lock.notify();
+
+ if (_dispatcherLogger.isDebugEnabled())
+ {
+ _dispatcherLogger.debug("Set Dispatcher Connection " + (connectionStopped ? "Stopped" : "Started")
+ + ": Currently " + (currently ? "Stopped" : "Started"));
+ }
+ }
+
+ return currently;
+ }
+
+ private void dispatchMessage(UnprocessedMessage message)
+ {
+ if (message.getDeliverBody() != null)
+ {
+ final BasicMessageConsumer consumer =
+ (BasicMessageConsumer) _consumers.get(message.getDeliverBody().consumerTag);
+
+ if ((consumer == null) || consumer.isClosed())
+ {
+ if (_dispatcherLogger.isInfoEnabled())
+ {
+ if (consumer == null)
+ {
+ _dispatcherLogger.info("Dispatcher(" + dispatcherID + ")Received a message(" + System.identityHashCode(message) + ")" + "["
+ + message.getDeliverBody().deliveryTag + "] from queue "
+ + message.getDeliverBody().consumerTag + " )without a handler - rejecting(requeue)...");
+ }
+ else
+ {
+ _dispatcherLogger.info("Dispatcher(" + dispatcherID + ")Received a message(" + System.identityHashCode(message) + ") ["
+ + message.getDeliverBody().deliveryTag + "] from queue consumer("
+ + consumer.debugIdentity() + ") is closed rejecting(requeue)...");
+ }
+ }
+ // Don't reject if we're already closing
+ if (!_dispatcherClosed.get())
+ {
+ rejectMessage(message, true);
+ }
+ }
+ else
+ {
+ consumer.notifyMessage(message, _channelId);
+ }
+ }
+ }
+ }
+
+ /*public void requestAccess(AMQShortString realm, boolean exclusive, boolean passive, boolean active, boolean write,
+ boolean read) throws AMQException
+ {
+ getProtocolHandler().writeCommandFrameAndWaitForReply(AccessRequestBody.createAMQFrame(getChannelId(),
+ getProtocolMajorVersion(), getProtocolMinorVersion(), active, exclusive, passive, read, realm, write),
+ new BlockingMethodFrameListener(_channelId)
+ {
+
+ public boolean processMethod(int channelId, AMQMethodBody frame) // throws AMQException
+ {
+ if (frame instanceof AccessRequestOkBody)
+ {
+ setTicket(((AccessRequestOkBody) frame).getTicket());
+
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ });
+ }*/
+
+ private class SuspenderRunner implements Runnable
+ {
+ private boolean _suspend;
+
+ public SuspenderRunner(boolean suspend)
+ {
+ _suspend = suspend;
+ }
+
+ public void run()
+ {
+ try
+ {
+ suspendChannel(_suspend);
+ }
+ catch (AMQException e)
+ {
+ _logger.warn("Unable to suspend channel");
+ }
+ }
+ }
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/client/AMQSessionAdapter.java b/Final/java/client/src/main/java/org/apache/qpid/client/AMQSessionAdapter.java
new file mode 100644
index 0000000000..93f10761e2
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/AMQSessionAdapter.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.client;
+
+public interface AMQSessionAdapter
+{
+ public AMQSession getSession();
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/client/AMQTemporaryQueue.java b/Final/java/client/src/main/java/org/apache/qpid/client/AMQTemporaryQueue.java
new file mode 100644
index 0000000000..f54cb782c8
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/AMQTemporaryQueue.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.client;
+
+import javax.jms.JMSException;
+import javax.jms.TemporaryQueue;
+
+import org.apache.qpid.framing.AMQShortString;
+
+import java.util.Random;
+import java.util.UUID;
+
+/** AMQ implementation of a TemporaryQueue. */
+final class AMQTemporaryQueue extends AMQQueue implements TemporaryQueue, TemporaryDestination
+{
+
+
+ private final AMQSession _session;
+ private boolean _deleted;
+
+ /** Create a new instance of an AMQTemporaryQueue */
+ public AMQTemporaryQueue(AMQSession session)
+ {
+ super(session.getTemporaryQueueExchangeName(), new AMQShortString("TempQueue" + UUID.randomUUID()), true);
+ _session = session;
+ }
+
+ /** @see javax.jms.TemporaryQueue#delete() */
+ public synchronized void delete() throws JMSException
+ {
+ if (_session.hasConsumer(this))
+ {
+ throw new JMSException("Temporary Queue has consumers so cannot be deleted");
+ }
+ _deleted = true;
+
+ // Currently TemporaryQueue is set to be auto-delete which means that the queue will be deleted
+ // by the server when there are no more subscriptions to that queue. This is probably not
+ // quite right for JMSCompliance.
+ }
+
+ public AMQSession getSession()
+ {
+ return _session;
+ }
+
+ public boolean isDeleted()
+ {
+ return _deleted;
+ }
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/client/AMQTemporaryTopic.java b/Final/java/client/src/main/java/org/apache/qpid/client/AMQTemporaryTopic.java
new file mode 100644
index 0000000000..7b5781530b
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/AMQTemporaryTopic.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.client;
+
+import org.apache.qpid.framing.AMQShortString;
+
+import javax.jms.JMSException;
+import javax.jms.TemporaryTopic;
+import java.util.UUID;
+
+/**
+ * AMQ implementation of TemporaryTopic.
+ */
+class AMQTemporaryTopic extends AMQTopic implements TemporaryTopic, TemporaryDestination
+{
+
+ private final AMQSession _session;
+ private boolean _deleted;
+ /**
+ * Create new temporary topic.
+ */
+ public AMQTemporaryTopic(AMQSession session)
+ {
+ super(session.getTemporaryTopicExchangeName(),new AMQShortString("tmp_" + UUID.randomUUID()));
+ _session = session;
+ }
+
+ /**
+ * @see javax.jms.TemporaryTopic#delete()
+ */
+ public void delete() throws JMSException
+ {
+ if(_session.hasConsumer(this))
+ {
+ throw new JMSException("Temporary Topic has consumers so cannot be deleted");
+ }
+
+ _deleted = true;
+ // Currently TemporaryQueue is set to be auto-delete which means that the queue will be deleted
+ // by the server when there are no more subscriptions to that queue. This is probably not
+ // quite right for JMSCompliance.
+ }
+
+ public AMQSession getSession()
+ {
+ return _session;
+ }
+
+ public boolean isDeleted()
+ {
+ return _deleted;
+ }
+
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/client/AMQTopic.java b/Final/java/client/src/main/java/org/apache/qpid/client/AMQTopic.java
new file mode 100644
index 0000000000..319e728edf
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/AMQTopic.java
@@ -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.
+ *
+ */
+package org.apache.qpid.client;
+
+import javax.jms.JMSException;
+import javax.jms.Topic;
+
+import org.apache.qpid.exchange.ExchangeDefaults;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.url.BindingURL;
+
+public class AMQTopic extends AMQDestination implements Topic
+{
+ /**
+ * Constructor for use in creating a topic using a BindingURL.
+ *
+ * @param binding The binding url object.
+ */
+ public AMQTopic(BindingURL binding)
+ {
+ super(binding);
+ }
+
+// public AMQTopic(String exchangeName, String routingKey)
+// {
+// this(new AMQShortString(exchangeName), new AMQShortString(routingKey));
+// }
+
+ public AMQTopic(AMQShortString exchange, AMQShortString routingKey, AMQShortString queueName)
+ {
+ super(exchange, ExchangeDefaults.TOPIC_EXCHANGE_CLASS, routingKey, true, true, queueName, false);
+ }
+
+ public AMQTopic(AMQConnection conn, String routingKey)
+ {
+ this(conn.getDefaultTopicExchangeName(), new AMQShortString(routingKey));
+ }
+
+
+ public AMQTopic(AMQShortString exchangeName, String routingKey)
+ {
+ this(exchangeName, new AMQShortString(routingKey));
+ }
+
+ public AMQTopic(AMQShortString exchangeName, AMQShortString routingKey)
+ {
+ this(exchangeName, routingKey, null);
+ }
+
+ public AMQTopic(AMQShortString exchangeName, AMQShortString name, boolean isAutoDelete, AMQShortString queueName, boolean isDurable)
+ {
+ super(exchangeName, ExchangeDefaults.TOPIC_EXCHANGE_CLASS, name, true, isAutoDelete,
+ queueName, isDurable);
+ }
+
+ public static AMQTopic createDurableTopic(AMQTopic topic, String subscriptionName, AMQConnection connection)
+ throws JMSException
+ {
+ return new AMQTopic(topic.getExchangeName(), topic.getDestinationName(), false,
+ getDurableTopicQueueName(subscriptionName, connection),
+ true);
+ }
+
+ public static AMQShortString getDurableTopicQueueName(String subscriptionName, AMQConnection connection) throws JMSException
+ {
+ return new AMQShortString(connection.getClientID() + ":" + subscriptionName);
+ }
+
+ public String getTopicName() throws JMSException
+ {
+ return super.getDestinationName().toString();
+ }
+
+ public AMQShortString getRoutingKey()
+ {
+ return getDestinationName();
+ }
+
+ public boolean isNameRequired()
+ {
+ // Topics always rely on a server generated queue name.
+ return false;
+ }
+
+ /**
+ * Override since the queue is always private and we must ensure it remains null. If not,
+ * reuse of the topic when registering consumers will make all consumers listen on the same (private) queue rather
+ * than getting their own (private) queue.
+ * <p/>
+ * This is relatively nasty but it is difficult to come up with a more elegant solution, given
+ * the requirement in the case on AMQQueue and possibly other AMQDestination subclasses to
+ * use the underlying queue name even where it is server generated.
+ */
+ public void setQueueName(String queueName)
+ {
+ }
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/client/AMQTopicSessionAdaptor.java b/Final/java/client/src/main/java/org/apache/qpid/client/AMQTopicSessionAdaptor.java
new file mode 100644
index 0000000000..f44f8414fa
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/AMQTopicSessionAdaptor.java
@@ -0,0 +1,226 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.client;
+
+import java.io.Serializable;
+
+import javax.jms.BytesMessage;
+import javax.jms.Destination;
+import javax.jms.IllegalStateException;
+import javax.jms.JMSException;
+import javax.jms.MapMessage;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageListener;
+import javax.jms.MessageProducer;
+import javax.jms.ObjectMessage;
+import javax.jms.Queue;
+import javax.jms.QueueBrowser;
+import javax.jms.Session;
+import javax.jms.StreamMessage;
+import javax.jms.TemporaryQueue;
+import javax.jms.TemporaryTopic;
+import javax.jms.TextMessage;
+import javax.jms.Topic;
+import javax.jms.TopicPublisher;
+import javax.jms.TopicSession;
+import javax.jms.TopicSubscriber;
+
+public class AMQTopicSessionAdaptor implements TopicSession, AMQSessionAdapter
+{
+ protected final AMQSession _session;
+
+ public AMQTopicSessionAdaptor(Session session)
+ {
+ _session = (AMQSession) session;
+ }
+
+ public Topic createTopic(String string) throws JMSException
+ {
+ return _session.createTopic(string);
+ }
+
+ public TopicSubscriber createSubscriber(Topic topic) throws JMSException
+ {
+ return _session.createSubscriber(topic);
+ }
+
+ public TopicSubscriber createSubscriber(Topic topic, String string, boolean b) throws JMSException
+ {
+ return _session.createSubscriber(topic, string, b);
+ }
+
+ public TopicSubscriber createDurableSubscriber(Topic topic, String string) throws JMSException
+ {
+ return _session.createDurableSubscriber(topic, string);
+ }
+
+ public TopicSubscriber createDurableSubscriber(Topic topic, String string, String string1, boolean b) throws JMSException
+ {
+ return _session.createDurableSubscriber(topic, string, string1, b);
+ }
+
+ public TopicPublisher createPublisher(Topic topic) throws JMSException
+ {
+ return _session.createPublisher(topic);
+ }
+
+ public TemporaryTopic createTemporaryTopic() throws JMSException
+ {
+ return _session.createTemporaryTopic();
+ }
+
+ public void unsubscribe(String string) throws JMSException
+ {
+ _session.unsubscribe(string);
+ }
+
+ public BytesMessage createBytesMessage() throws JMSException
+ {
+ return _session.createBytesMessage();
+ }
+
+ public MapMessage createMapMessage() throws JMSException
+ {
+ return _session.createMapMessage();
+ }
+
+ public Message createMessage() throws JMSException
+ {
+ return _session.createMessage();
+ }
+
+ public ObjectMessage createObjectMessage() throws JMSException
+ {
+ return _session.createObjectMessage();
+ }
+
+ public ObjectMessage createObjectMessage(Serializable serializable) throws JMSException
+ {
+ return _session.createObjectMessage();
+ }
+
+ public StreamMessage createStreamMessage() throws JMSException
+ {
+ return _session.createStreamMessage();
+ }
+
+ public TextMessage createTextMessage() throws JMSException
+ {
+ return _session.createTextMessage();
+ }
+
+ public TextMessage createTextMessage(String string) throws JMSException
+ {
+ return _session.createTextMessage(string);
+ }
+
+ public boolean getTransacted() throws JMSException
+ {
+ return _session.getTransacted();
+ }
+
+ public int getAcknowledgeMode() throws JMSException
+ {
+ return _session.getAcknowledgeMode();
+ }
+
+ public void commit() throws JMSException
+ {
+ _session.commit();
+ }
+
+ public void rollback() throws JMSException
+ {
+ _session.rollback();
+ }
+
+ public void close() throws JMSException
+ {
+ _session.close();
+ }
+
+ public void recover() throws JMSException
+ {
+ _session.recover();
+ }
+
+ public MessageListener getMessageListener() throws JMSException
+ {
+ return _session.getMessageListener();
+ }
+
+ public void setMessageListener(MessageListener messageListener) throws JMSException
+ {
+ _session.setMessageListener(messageListener);
+ }
+
+ public void run()
+ {
+ _session.run();
+ }
+
+ public MessageProducer createProducer(Destination destination) throws JMSException
+ {
+ return _session.createProducer(destination);
+ }
+
+ public MessageConsumer createConsumer(Destination destination) throws JMSException
+ {
+ return _session.createConsumer(destination);
+ }
+
+ public MessageConsumer createConsumer(Destination destination, String string) throws JMSException
+ {
+ return _session.createConsumer(destination, string);
+ }
+
+ public MessageConsumer createConsumer(Destination destination, String string, boolean b) throws JMSException
+ {
+ return _session.createConsumer(destination, string, b);
+ }
+
+ //The following methods cannot be called from a TopicSession as per JMS spec
+ public Queue createQueue(String string) throws JMSException
+ {
+ throw new IllegalStateException("Cannot call createQueue from TopicSession");
+ }
+
+ public QueueBrowser createBrowser(Queue queue) throws JMSException
+ {
+ throw new IllegalStateException("Cannot call createBrowser from TopicSession");
+ }
+
+ public QueueBrowser createBrowser(Queue queue, String string) throws JMSException
+ {
+ throw new IllegalStateException("Cannot call createBrowser from TopicSession");
+ }
+
+ public TemporaryQueue createTemporaryQueue() throws JMSException
+ {
+ throw new IllegalStateException("Cannot call createTemporaryQueue from TopicSession");
+ }
+
+ public AMQSession getSession()
+ {
+ return _session;
+ }
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/client/AMQUndefinedDestination.java b/Final/java/client/src/main/java/org/apache/qpid/client/AMQUndefinedDestination.java
new file mode 100644
index 0000000000..0f3723c58b
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/AMQUndefinedDestination.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.client;
+
+import org.apache.qpid.framing.AMQShortString;
+
+public class AMQUndefinedDestination extends AMQDestination
+{
+
+ private static final AMQShortString UNKNOWN_EXCHANGE_CLASS = new AMQShortString("unknown");
+
+
+ public AMQUndefinedDestination(AMQShortString exchange, AMQShortString routingKey, AMQShortString queueName)
+ {
+ super(exchange, UNKNOWN_EXCHANGE_CLASS, routingKey, queueName);
+ }
+
+ public AMQShortString getRoutingKey()
+ {
+ return getDestinationName();
+ }
+
+ public boolean isNameRequired()
+ {
+ return getAMQQueueName() == null;
+ }
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/client/BasicMessageConsumer.java b/Final/java/client/src/main/java/org/apache/qpid/client/BasicMessageConsumer.java
new file mode 100644
index 0000000000..ddaf0cfd93
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/BasicMessageConsumer.java
@@ -0,0 +1,996 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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.failover.FailoverException;
+import org.apache.qpid.client.message.AbstractJMSMessage;
+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.framing.AMQFrame;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.framing.BasicCancelBody;
+import org.apache.qpid.framing.BasicCancelOkBody;
+import org.apache.qpid.framing.FieldTable;
+import org.apache.qpid.jms.MessageConsumer;
+import org.apache.qpid.jms.Session;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageListener;
+
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicReference;
+
+public class BasicMessageConsumer extends Closeable implements MessageConsumer
+{
+ private static final Logger _logger = LoggerFactory.getLogger(BasicMessageConsumer.class);
+
+ /** The connection being used by this consumer */
+ private AMQConnection _connection;
+
+ private String _messageSelector;
+
+ private boolean _noLocal;
+
+ private AMQDestination _destination;
+
+ /** When true indicates that a blocking receive call is in progress */
+ private final AtomicBoolean _receiving = new AtomicBoolean(false);
+ /** Holds an atomic reference to the listener installed. */
+ private final AtomicReference<MessageListener> _messageListener = new AtomicReference<MessageListener>();
+
+ /** The consumer tag allows us to close the consumer by sending a jmsCancel method to the broker */
+ private AMQShortString _consumerTag;
+
+ /** We need to know the channel id when constructing frames */
+ private int _channelId;
+
+ /**
+ * 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
+ */
+ private final ArrayBlockingQueue _synchronousQueue;
+
+ private MessageFactoryRegistry _messageFactory;
+
+ private final AMQSession _session;
+
+ private AMQProtocolHandler _protocolHandler;
+
+ /** We need to store the "raw" field table so that we can resubscribe in the event of failover being required */
+ private FieldTable _rawSelectorFieldTable;
+
+ /**
+ * We store the high water prefetch field in order to be able to reuse it when resubscribing in the event of
+ * failover
+ */
+ private int _prefetchHigh;
+
+ /**
+ * We store the low water prefetch field in order to be able to reuse it when resubscribing in the event of
+ * failover
+ */
+ private int _prefetchLow;
+
+ /** We store the exclusive field in order to be able to reuse it when resubscribing in the event of failover */
+ private boolean _exclusive;
+
+ /**
+ * The acknowledge mode in force for this consumer. Note that the AMQP protocol allows different ack modes per
+ * consumer whereas JMS defines this at the session level, hence why we associate it with the consumer in our
+ * implementation.
+ */
+ private int _acknowledgeMode;
+
+ /** Number of messages unacknowledged in DUPS_OK_ACKNOWLEDGE mode */
+ private int _outstanding;
+
+ /**
+ * Switch to enable sending of acknowledgements when using DUPS_OK_ACKNOWLEDGE mode. Enabled when _outstannding
+ * number of msgs >= _prefetchHigh and disabled at < _prefetchLow
+ */
+ private boolean _dups_ok_acknowledge_send;
+
+ private ConcurrentLinkedQueue<Long> _unacknowledgedDeliveryTags = new ConcurrentLinkedQueue<Long>();
+
+ /** List of tags delievered, The last of which which should be acknowledged on commit in transaction mode. */
+ private ConcurrentLinkedQueue<Long> _receivedDeliveryTags = new ConcurrentLinkedQueue<Long>();
+
+ /**
+ * The thread that was used to call receive(). This is important for being able to interrupt that thread if a
+ * receive() is in progress.
+ */
+ private Thread _receivingThread;
+
+ /**
+ * autoClose denotes that the consumer will automatically cancel itself when there are no more messages to receive
+ * on the queue. This is used for queue browsing.
+ */
+ private boolean _autoClose;
+ private boolean _closeWhenNoMessages;
+
+ private boolean _noConsume;
+ private List<StackTraceElement> _closedStack = null;
+
+ protected BasicMessageConsumer(int channelId, AMQConnection connection, AMQDestination destination,
+ String messageSelector, boolean noLocal, MessageFactoryRegistry messageFactory, AMQSession session,
+ AMQProtocolHandler protocolHandler, FieldTable rawSelectorFieldTable, int prefetchHigh, int prefetchLow,
+ boolean exclusive, int acknowledgeMode, boolean noConsume, boolean autoClose)
+ {
+ _channelId = channelId;
+ _connection = connection;
+ _messageSelector = messageSelector;
+ _noLocal = noLocal;
+ _destination = destination;
+ _messageFactory = messageFactory;
+ _session = session;
+ _protocolHandler = protocolHandler;
+ _rawSelectorFieldTable = rawSelectorFieldTable;
+ _prefetchHigh = prefetchHigh;
+ _prefetchLow = prefetchLow;
+ _exclusive = exclusive;
+ _acknowledgeMode = acknowledgeMode;
+ _synchronousQueue = new ArrayBlockingQueue(prefetchHigh, true);
+ _autoClose = autoClose;
+ _noConsume = noConsume;
+
+ // Force queue browsers not to use acknowledge modes.
+ if (_noConsume)
+ {
+ _acknowledgeMode = Session.NO_ACKNOWLEDGE;
+ }
+ }
+
+ public AMQDestination getDestination()
+ {
+ return _destination;
+ }
+
+ public String getMessageSelector() throws JMSException
+ {
+ checkPreConditions();
+
+ return _messageSelector;
+ }
+
+ public MessageListener getMessageListener() throws JMSException
+ {
+ checkPreConditions();
+
+ return _messageListener.get();
+ }
+
+ public int getAcknowledgeMode()
+ {
+ return _acknowledgeMode;
+ }
+
+ private boolean isMessageListenerSet()
+ {
+ return _messageListener.get() != null;
+ }
+
+ public void setMessageListener(final MessageListener messageListener) throws JMSException
+ {
+ checkPreConditions();
+
+ // if the current listener is non-null and the session is not stopped, then
+ // it is an error to call this method.
+
+ // i.e. it is only valid to call this method if
+ //
+ // (a) the connection is stopped, in which case the dispatcher is not running
+ // OR
+ // (b) the listener is null AND we are not receiving synchronously at present
+ //
+
+ if (!_session.getAMQConnection().started())
+ {
+ _messageListener.set(messageListener);
+ _session.setHasMessageListeners();
+
+ if (_logger.isDebugEnabled())
+ {
+ _logger.debug("Session stopped : Message listener(" + messageListener + ") set for destination "
+ + _destination);
+ }
+ }
+ else
+ {
+ if (_receiving.get())
+ {
+ throw new javax.jms.IllegalStateException("Another thread is already receiving synchronously.");
+ }
+
+ if (!_messageListener.compareAndSet(null, messageListener))
+ {
+ throw new javax.jms.IllegalStateException("Attempt to alter listener while session is started.");
+ }
+
+ _logger.debug("Message listener set for destination " + _destination);
+
+ if (messageListener != null)
+ {
+ //todo: handle case where connection has already been started, and the dispatcher has alreaded started
+ // putting values on the _synchronousQueue
+
+ _messageListener.set(messageListener);
+ _session.setHasMessageListeners();
+ _session.startDistpatcherIfNecessary();
+ }
+ }
+ }
+
+ private void preApplicationProcessing(AbstractJMSMessage msg) throws JMSException
+ {
+
+ switch (_acknowledgeMode)
+ {
+
+ case Session.CLIENT_ACKNOWLEDGE:
+ _unacknowledgedDeliveryTags.add(msg.getDeliveryTag());
+ break;
+
+ case Session.SESSION_TRANSACTED:
+ if (isNoConsume())
+ {
+ _session.acknowledgeMessage(msg.getDeliveryTag(), false);
+ }
+ else
+ {
+ _logger.info("Recording tag for commit:" + msg.getDeliveryTag());
+ _receivedDeliveryTags.add(msg.getDeliveryTag());
+ }
+
+ break;
+ }
+
+ _session.setInRecovery(false);
+ }
+
+ private void acquireReceiving() throws JMSException
+ {
+ if (!_receiving.compareAndSet(false, true))
+ {
+ throw new javax.jms.IllegalStateException("Another thread is already receiving.");
+ }
+
+ if (isMessageListenerSet())
+ {
+ throw new javax.jms.IllegalStateException("A listener has already been set.");
+ }
+
+ _receivingThread = Thread.currentThread();
+ }
+
+ private void releaseReceiving()
+ {
+ _receiving.set(false);
+ _receivingThread = null;
+ }
+
+ public FieldTable getRawSelectorFieldTable()
+ {
+ return _rawSelectorFieldTable;
+ }
+
+ public int getPrefetch()
+ {
+ return _prefetchHigh;
+ }
+
+ public int getPrefetchHigh()
+ {
+ return _prefetchHigh;
+ }
+
+ public int getPrefetchLow()
+ {
+ return _prefetchLow;
+ }
+
+ public boolean isNoLocal()
+ {
+ return _noLocal;
+ }
+
+ public boolean isExclusive()
+ {
+ return _exclusive;
+ }
+
+ public boolean isReceiving()
+ {
+ return _receiving.get();
+ }
+
+ public Message receive() throws JMSException
+ {
+ return receive(0);
+ }
+
+ public Message receive(long l) throws JMSException
+ {
+
+ checkPreConditions();
+
+ acquireReceiving();
+
+ _session.startDistpatcherIfNecessary();
+
+ try
+ {
+ if (closeOnAutoClose())
+ {
+ return null;
+ }
+
+ Object o = null;
+ if (l > 0)
+ {
+ long endtime = System.currentTimeMillis() + l;
+ while (System.currentTimeMillis() < endtime && o == null)
+ {
+ try
+ {
+ o = _synchronousQueue.poll(endtime - System.currentTimeMillis(), TimeUnit.MILLISECONDS);
+ }
+ catch (InterruptedException e)
+ {
+ _logger.warn("Interrupted: " + e);
+ if (isClosed())
+ {
+ return null;
+ }
+ }
+ }
+ }
+ else
+ {
+ while (o == null)
+ {
+ try
+ {
+ o = _synchronousQueue.take();
+ }
+ catch (InterruptedException e)
+ {
+ _logger.warn("Interrupted: " + e);
+ if (isClosed())
+ {
+ return null;
+ }
+ }
+ }
+ }
+ final AbstractJMSMessage m = returnMessageOrThrow(o);
+ if (m != null)
+ {
+ preApplicationProcessing(m);
+ postDeliver(m);
+ }
+ return m;
+ }
+ finally
+ {
+ releaseReceiving();
+ }
+ }
+
+ private boolean closeOnAutoClose() throws JMSException
+ {
+ if (isAutoClose() && _closeWhenNoMessages && _synchronousQueue.isEmpty())
+ {
+ close(false);
+
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ public Message receiveNoWait() throws JMSException
+ {
+ checkPreConditions();
+
+ acquireReceiving();
+
+ _session.startDistpatcherIfNecessary();
+
+ try
+ {
+ if (closeOnAutoClose())
+ {
+ return null;
+ }
+
+ Object o = _synchronousQueue.poll();
+ final AbstractJMSMessage m = returnMessageOrThrow(o);
+ if (m != null)
+ {
+ preApplicationProcessing(m);
+ postDeliver(m);
+ }
+
+ return m;
+ }
+ finally
+ {
+ releaseReceiving();
+ }
+ }
+
+ /**
+ * We can get back either a Message or an exception from the queue. This method examines the argument and deals with
+ * it by throwing it (if an exception) or returning it (in any other case).
+ *
+ * @param o
+ *
+ * @return a message only if o is a Message
+ *
+ * @throws JMSException if the argument is a throwable. If it is a JMSException it is rethrown as is, but if not a
+ * JMSException is created with the linked exception set appropriately
+ */
+ private AbstractJMSMessage returnMessageOrThrow(Object o) throws JMSException
+ {
+ // errors are passed via the queue too since there is no way of interrupting the poll() via the API.
+ if (o instanceof Throwable)
+ {
+ JMSException e = new JMSException("Message consumer forcibly closed due to error: " + o);
+ if (o instanceof Exception)
+ {
+ e.setLinkedException((Exception) o);
+ }
+
+ throw e;
+ }
+ else
+ {
+ return (AbstractJMSMessage) o;
+ }
+ }
+
+ public void close() throws JMSException
+ {
+ close(true);
+ }
+
+ public void close(boolean sendClose) throws JMSException
+ {
+ // synchronized (_closed)
+
+ if (_logger.isInfoEnabled())
+ {
+ _logger.info("Closing consumer:" + debugIdentity());
+ }
+
+ synchronized (_connection.getFailoverMutex())
+ {
+ if (!_closed.getAndSet(true))
+ {
+ if (_logger.isTraceEnabled())
+ {
+ StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
+ if (_closedStack != null)
+ {
+ _logger.trace(_consumerTag + " previously:" + _closedStack.toString());
+ }
+ else
+ {
+ _closedStack = Arrays.asList(stackTrace).subList(3, stackTrace.length - 1);
+ }
+ }
+
+ if (sendClose)
+ {
+ // TODO: Be aware of possible changes to parameter order as versions change.
+ final AMQFrame cancelFrame =
+ BasicCancelBody.createAMQFrame(_channelId, _protocolHandler.getProtocolMajorVersion(),
+ _protocolHandler.getProtocolMinorVersion(), _consumerTag, // consumerTag
+ false); // nowait
+
+ try
+ {
+ _protocolHandler.syncWrite(cancelFrame, BasicCancelOkBody.class);
+
+ if (_logger.isDebugEnabled())
+ {
+ _logger.debug("CancelOk'd for consumer:" + debugIdentity());
+ }
+
+ }
+ catch (AMQException e)
+ {
+ throw new JMSAMQException("Error closing consumer: " + e, e);
+ }
+ catch (FailoverException e)
+ {
+ throw new JMSAMQException("FailoverException interrupted basic cancel.", e);
+ }
+ }
+ else
+ {
+ // //fixme this probably is not right
+ // if (!isNoConsume())
+ { // done in BasicCancelOK Handler but not sending one so just deregister.
+ deregisterConsumer();
+ }
+ }
+
+ if ((_messageListener != null) && _receiving.get())
+ {
+ if (_logger.isInfoEnabled())
+ {
+ _logger.info("Interrupting thread: " + _receivingThread);
+ }
+
+ _receivingThread.interrupt();
+ }
+ }
+ }
+ }
+
+ /**
+ * Called when you need to invalidate a consumer. Used for example when failover has occurred and the client has
+ * vetoed automatic resubscription. The caller must hold the failover mutex.
+ */
+ void markClosed()
+ {
+ // synchronized (_closed)
+ {
+ _closed.set(true);
+
+ if (_logger.isTraceEnabled())
+ {
+ StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
+ if (_closedStack != null)
+ {
+ _logger.trace(_consumerTag + " markClosed():"
+ + Arrays.asList(stackTrace).subList(3, stackTrace.length - 1));
+ _logger.trace(_consumerTag + " previously:" + _closedStack.toString());
+ }
+ else
+ {
+ _closedStack = Arrays.asList(stackTrace).subList(3, stackTrace.length - 1);
+ }
+ }
+ }
+
+ deregisterConsumer();
+ }
+
+ /**
+ * Called from the AMQSession when a message has arrived for this consumer. This methods handles both the case of a
+ * message listener or a synchronous receive() caller.
+ *
+ * @param messageFrame the raw unprocessed mesage
+ * @param channelId channel on which this message was sent
+ */
+ void notifyMessage(UnprocessedMessage messageFrame, int channelId)
+ {
+ final boolean debug = _logger.isDebugEnabled();
+
+ if (debug)
+ {
+ _logger.debug("notifyMessage called with message number " + messageFrame.getDeliverBody().deliveryTag);
+ }
+
+ try
+ {
+ AbstractJMSMessage jmsMessage =
+ _messageFactory.createMessage(messageFrame.getDeliverBody().deliveryTag,
+ messageFrame.getDeliverBody().redelivered, messageFrame.getDeliverBody().exchange,
+ messageFrame.getDeliverBody().routingKey, messageFrame.getContentHeader(), messageFrame.getBodies());
+
+ if (debug)
+ {
+ _logger.debug("Message is of type: " + jmsMessage.getClass().getName());
+ }
+ // synchronized (_closed)
+
+ {
+ // if (!_closed.get())
+ {
+
+ jmsMessage.setConsumer(this);
+
+ preDeliver(jmsMessage);
+
+ notifyMessage(jmsMessage, channelId);
+ }
+ // else
+ // {
+ // _logger.error("MESSAGE REJECTING!");
+ // _session.rejectMessage(jmsMessage, true);
+ // //_logger.error("MESSAGE JUST DROPPED!");
+ // }
+ }
+ }
+ catch (Exception e)
+ {
+ if (e instanceof InterruptedException)
+ {
+ _logger.info("SynchronousQueue.put interupted. Usually result of connection closing");
+ }
+ else
+ {
+ _logger.error("Caught exception (dump follows) - ignoring...", e);
+ }
+ }
+ }
+
+ /**
+ * @param jmsMessage this message has already been processed so can't redo preDeliver
+ * @param channelId
+ */
+ public void notifyMessage(AbstractJMSMessage jmsMessage, int channelId)
+ {
+ try
+ {
+ if (isMessageListenerSet())
+ {
+ // we do not need a lock around the test above, and the dispatch below as it is invalid
+ // for an application to alter an installed listener while the session is started
+ // synchronized (_closed)
+ {
+ // if (!_closed.get())
+ {
+
+ preApplicationProcessing(jmsMessage);
+ getMessageListener().onMessage(jmsMessage);
+ postDeliver(jmsMessage);
+ }
+ }
+ }
+ else
+ {
+ _synchronousQueue.put(jmsMessage);
+ }
+ }
+ catch (Exception e)
+ {
+ if (e instanceof InterruptedException)
+ {
+ _logger.info("reNotification : SynchronousQueue.put interupted. Usually result of connection closing");
+ }
+ else
+ {
+ _logger.error("reNotification : Caught exception (dump follows) - ignoring...", e);
+ }
+ }
+ }
+
+ private void preDeliver(AbstractJMSMessage msg)
+ {
+ switch (_acknowledgeMode)
+ {
+
+ case Session.PRE_ACKNOWLEDGE:
+ _session.acknowledgeMessage(msg.getDeliveryTag(), false);
+ break;
+
+ case Session.CLIENT_ACKNOWLEDGE:
+ // we set the session so that when the user calls acknowledge() it can call the method on session
+ // to send out the appropriate frame
+ msg.setAMQSession(_session);
+ break;
+ }
+ }
+
+ private void postDeliver(AbstractJMSMessage msg) throws JMSException
+ {
+ msg.setJMSDestination(_destination);
+ switch (_acknowledgeMode)
+ {
+
+ case Session.CLIENT_ACKNOWLEDGE:
+ if (isNoConsume())
+ {
+ _session.acknowledgeMessage(msg.getDeliveryTag(), false);
+ }
+
+ break;
+
+ case Session.DUPS_OK_ACKNOWLEDGE:
+ if (++_outstanding >= _prefetchHigh)
+ {
+ _dups_ok_acknowledge_send = true;
+ }
+
+ if (_outstanding <= _prefetchLow)
+ {
+ _dups_ok_acknowledge_send = false;
+ }
+
+ if (_dups_ok_acknowledge_send)
+ {
+ if (!_session.isInRecovery())
+ {
+ _session.acknowledgeMessage(msg.getDeliveryTag(), true);
+ }
+ }
+
+ break;
+
+ case Session.AUTO_ACKNOWLEDGE:
+ // we do not auto ack a message if the application code called recover()
+ if (!_session.isInRecovery())
+ {
+ _session.acknowledgeMessage(msg.getDeliveryTag(), false);
+ }
+
+ break;
+ }
+ }
+
+ /** Acknowledge up to last message delivered (if any). Used when commiting. */
+ void acknowledgeLastDelivered()
+ {
+ if (!_receivedDeliveryTags.isEmpty())
+ {
+ long lastDeliveryTag = _receivedDeliveryTags.poll();
+
+ while (!_receivedDeliveryTags.isEmpty())
+ {
+ lastDeliveryTag = _receivedDeliveryTags.poll();
+ }
+
+ assert _receivedDeliveryTags.isEmpty();
+
+ _session.acknowledgeMessage(lastDeliveryTag, true);
+ }
+ }
+
+ void notifyError(Throwable cause)
+ {
+ // synchronized (_closed)
+ {
+ _closed.set(true);
+ if (_logger.isTraceEnabled())
+ {
+ StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
+ if (_closedStack != null)
+ {
+ _logger.trace(_consumerTag + " notifyError():"
+ + Arrays.asList(stackTrace).subList(3, stackTrace.length - 1));
+ _logger.trace(_consumerTag + " previously" + _closedStack.toString());
+ }
+ else
+ {
+ _closedStack = Arrays.asList(stackTrace).subList(3, stackTrace.length - 1);
+ }
+ }
+ }
+ // QPID-293 can "request redelivery of this error through dispatcher"
+
+ // we have no way of propagating the exception to a message listener - a JMS limitation - so we
+ // deal with the case where we have a synchronous receive() waiting for a message to arrive
+ if (!isMessageListenerSet())
+ {
+ // offer only succeeds if there is a thread waiting for an item from the queue
+ if (_synchronousQueue.offer(cause))
+ {
+ _logger.debug("Passed exception to synchronous queue for propagation to receive()");
+ }
+ }
+
+ deregisterConsumer();
+ }
+
+ /**
+ * Perform cleanup to deregister this consumer. This occurs when closing the consumer in both the clean case and in
+ * the case of an error occurring.
+ */
+ private void deregisterConsumer()
+ {
+ _session.deregisterConsumer(this);
+ }
+
+ public AMQShortString getConsumerTag()
+ {
+ return _consumerTag;
+ }
+
+ public void setConsumerTag(AMQShortString consumerTag)
+ {
+ _consumerTag = consumerTag;
+ }
+
+ public AMQSession getSession()
+ {
+ return _session;
+ }
+
+ private void checkPreConditions() throws JMSException
+ {
+
+ this.checkNotClosed();
+
+ if ((_session == null) || _session.isClosed())
+ {
+ throw new javax.jms.IllegalStateException("Invalid Session");
+ }
+ }
+
+ public void acknowledge() // throws JMSException
+ {
+ if (!isClosed())
+ {
+
+ Iterator<Long> tags = _unacknowledgedDeliveryTags.iterator();
+ while (tags.hasNext())
+ {
+ _session.acknowledgeMessage(tags.next(), false);
+ tags.remove();
+ }
+ }
+ else
+ {
+ throw new IllegalStateException("Consumer is closed");
+ }
+ }
+
+ /** Called on recovery to reset the list of delivery tags */
+ public void clearUnackedMessages()
+ {
+ _unacknowledgedDeliveryTags.clear();
+ }
+
+ public boolean isAutoClose()
+ {
+ return _autoClose;
+ }
+
+ public boolean isNoConsume()
+ {
+ return _noConsume;
+ }
+
+ public void closeWhenNoMessages(boolean b)
+ {
+ _closeWhenNoMessages = b;
+
+ if (_closeWhenNoMessages && _synchronousQueue.isEmpty() && _receiving.get() && (_messageListener != null))
+ {
+ _closed.set(true);
+ _receivingThread.interrupt();
+ }
+
+ }
+
+ public void rollback()
+ {
+ clearUnackedMessages();
+
+ if (!_receivedDeliveryTags.isEmpty())
+ {
+ _logger.debug("Rejecting received messages in _receivedDTs (RQ)");
+ }
+
+ // rollback received but not committed messages
+ while (!_receivedDeliveryTags.isEmpty())
+ {
+ if (_logger.isDebugEnabled())
+ {
+ _logger.debug("Rejecting the messages(" + _receivedDeliveryTags.size() + ") in _receivedDTs (RQ)"
+ + "for consumer with tag:" + _consumerTag);
+ }
+
+ Long tag = _receivedDeliveryTags.poll();
+
+ if (tag != null)
+ {
+ if (_logger.isTraceEnabled())
+ {
+ _logger.trace("Rejecting tag from _receivedDTs:" + tag);
+ }
+
+ _session.rejectMessage(tag, true);
+ }
+ }
+
+ if (!_receivedDeliveryTags.isEmpty())
+ {
+ if (_logger.isDebugEnabled())
+ {
+ _logger.debug("Queue _receivedDTs (RQ) was not empty after rejection");
+ }
+ }
+
+ // rollback pending messages
+ if (_synchronousQueue.size() > 0)
+ {
+ if (_logger.isDebugEnabled())
+ {
+ _logger.debug("Rejecting the messages(" + _synchronousQueue.size() + ") in _syncQueue (PRQ)"
+ + "for consumer with tag:" + _consumerTag);
+ }
+
+ Iterator iterator = _synchronousQueue.iterator();
+
+ int initialSize = _synchronousQueue.size();
+
+ boolean removed = false;
+ while (iterator.hasNext())
+ {
+
+ Object o = iterator.next();
+ if (o instanceof AbstractJMSMessage)
+ {
+ _session.rejectMessage(((AbstractJMSMessage) o), true);
+
+ if (_logger.isTraceEnabled())
+ {
+ _logger.trace("Rejected message:" + ((AbstractJMSMessage) o).getDeliveryTag());
+ }
+
+ iterator.remove();
+ removed = true;
+
+ }
+ else
+ {
+ _logger.error("Queue contained a :" + o.getClass()
+ + " unable to reject as it is not an AbstractJMSMessage. Will be cleared");
+ iterator.remove();
+ removed = true;
+ }
+ }
+
+ if (removed && (initialSize == _synchronousQueue.size()))
+ {
+ _logger.error("Queue had content removed but didn't change in size." + initialSize);
+ }
+
+
+ if (_synchronousQueue.size() != 0)
+ {
+ _logger.warn("Queue was not empty after rejecting all messages Remaining:" + _synchronousQueue.size());
+ rollback();
+ }
+
+ clearReceiveQueue();
+ }
+ }
+
+ public String debugIdentity()
+ {
+ return String.valueOf(_consumerTag) + "[" + System.identityHashCode(this) + "]";
+ }
+
+ public void clearReceiveQueue()
+ {
+ _synchronousQueue.clear();
+ }
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/client/BasicMessageProducer.java b/Final/java/client/src/main/java/org/apache/qpid/client/BasicMessageProducer.java
new file mode 100644
index 0000000000..0ee4882ec2
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/BasicMessageProducer.java
@@ -0,0 +1,691 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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.mina.common.ByteBuffer;
+
+import org.apache.qpid.AMQException;
+import org.apache.qpid.client.message.AbstractJMSMessage;
+import org.apache.qpid.client.message.MessageConverter;
+import org.apache.qpid.client.protocol.AMQProtocolHandler;
+import org.apache.qpid.framing.AMQFrame;
+import org.apache.qpid.framing.BasicConsumeBody;
+import org.apache.qpid.framing.BasicContentHeaderProperties;
+import org.apache.qpid.framing.BasicPublishBody;
+import org.apache.qpid.framing.CompositeAMQDataBlock;
+import org.apache.qpid.framing.ContentBody;
+import org.apache.qpid.framing.ContentHeaderBody;
+import org.apache.qpid.framing.ExchangeDeclareBody;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.jms.BytesMessage;
+import javax.jms.DeliveryMode;
+import javax.jms.Destination;
+import javax.jms.InvalidDestinationException;
+import javax.jms.JMSException;
+import javax.jms.MapMessage;
+import javax.jms.Message;
+import javax.jms.ObjectMessage;
+import javax.jms.Queue;
+import javax.jms.StreamMessage;
+import javax.jms.TextMessage;
+import javax.jms.Topic;
+
+import java.io.UnsupportedEncodingException;
+import java.util.UUID;
+
+public class BasicMessageProducer extends Closeable implements org.apache.qpid.jms.MessageProducer
+{
+ protected final Logger _logger = LoggerFactory.getLogger(getClass());
+
+ private AMQConnection _connection;
+
+ /**
+ * If true, messages will not get a timestamp.
+ */
+ private boolean _disableTimestamps;
+
+ /**
+ * Priority of messages created by this producer.
+ */
+ private int _messagePriority;
+
+ /**
+ * Time to live of messages. Specified in milliseconds but AMQ has 1 second resolution.
+ */
+ private long _timeToLive;
+
+ /**
+ * Delivery mode used for this producer.
+ */
+ private int _deliveryMode = DeliveryMode.PERSISTENT;
+
+ /**
+ * The Destination used for this consumer, if specified upon creation.
+ */
+ protected AMQDestination _destination;
+
+ /**
+ * Default encoding used for messages produced by this producer.
+ */
+ private String _encoding;
+
+ /**
+ * Default encoding used for message produced by this producer.
+ */
+ private String _mimeType;
+
+ private AMQProtocolHandler _protocolHandler;
+
+ /**
+ * True if this producer was created from a transacted session
+ */
+ private boolean _transacted;
+
+ private int _channelId;
+
+ /**
+ * This is an id generated by the session and is used to tie individual producers to the session. This means we
+ * can deregister a producer with the session when the producer is clsoed. We need to be able to tie producers
+ * to the session so that when an error is propagated to the session it can close the producer (meaning that
+ * a client that happens to hold onto a producer reference will get an error if he tries to use it subsequently).
+ */
+ private long _producerId;
+
+ /**
+ * The session used to create this producer
+ */
+ private AMQSession _session;
+
+ private final boolean _immediate;
+
+ private final boolean _mandatory;
+
+ private final boolean _waitUntilSent;
+
+ private boolean _disableMessageId;
+
+ private static final ContentBody[] NO_CONTENT_BODIES = new ContentBody[0];
+
+ protected BasicMessageProducer(AMQConnection connection, AMQDestination destination, boolean transacted, int channelId,
+ AMQSession session, AMQProtocolHandler protocolHandler, long producerId, boolean immediate, boolean mandatory,
+ boolean waitUntilSent)
+ {
+ _connection = connection;
+ _destination = destination;
+ _transacted = transacted;
+ _protocolHandler = protocolHandler;
+ _channelId = channelId;
+ _session = session;
+ _producerId = producerId;
+ if (destination != null)
+ {
+ declareDestination(destination);
+ }
+
+ _immediate = immediate;
+ _mandatory = mandatory;
+ _waitUntilSent = waitUntilSent;
+ }
+
+ void resubscribe() throws AMQException
+ {
+ if (_destination != null)
+ {
+ declareDestination(_destination);
+ }
+ }
+
+ private void declareDestination(AMQDestination destination)
+ {
+ // Declare the exchange
+ // Note that the durable and internal arguments are ignored since passive is set to false
+ // TODO: Be aware of possible changes to parameter order as versions change.
+ AMQFrame declare =
+ ExchangeDeclareBody.createAMQFrame(_channelId, _protocolHandler.getProtocolMajorVersion(),
+ _protocolHandler.getProtocolMinorVersion(), null, // arguments
+ false, // autoDelete
+ false, // durable
+ destination.getExchangeName(), // exchange
+ false, // internal
+ true, // nowait
+ false, // passive
+ _session.getTicket(), // ticket
+ destination.getExchangeClass()); // type
+ _protocolHandler.writeFrame(declare);
+ }
+
+ public void setDisableMessageID(boolean b) throws JMSException
+ {
+ checkPreConditions();
+ checkNotClosed();
+ _disableMessageId = b;
+ }
+
+ public boolean getDisableMessageID() throws JMSException
+ {
+ checkNotClosed();
+
+ return _disableMessageId;
+ }
+
+ public void setDisableMessageTimestamp(boolean b) throws JMSException
+ {
+ checkPreConditions();
+ _disableTimestamps = b;
+ }
+
+ public boolean getDisableMessageTimestamp() throws JMSException
+ {
+ checkNotClosed();
+
+ return _disableTimestamps;
+ }
+
+ public void setDeliveryMode(int i) throws JMSException
+ {
+ checkPreConditions();
+ if ((i != DeliveryMode.NON_PERSISTENT) && (i != DeliveryMode.PERSISTENT))
+ {
+ throw new JMSException("DeliveryMode must be either NON_PERSISTENT or PERSISTENT. Value of " + i
+ + " is illegal");
+ }
+
+ _deliveryMode = i;
+ }
+
+ public int getDeliveryMode() throws JMSException
+ {
+ checkNotClosed();
+
+ return _deliveryMode;
+ }
+
+ public void setPriority(int i) throws JMSException
+ {
+ checkPreConditions();
+ if ((i < 0) || (i > 9))
+ {
+ throw new IllegalArgumentException("Priority of " + i + " is illegal. Value must be in range 0 to 9");
+ }
+
+ _messagePriority = i;
+ }
+
+ public int getPriority() throws JMSException
+ {
+ checkNotClosed();
+
+ return _messagePriority;
+ }
+
+ public void setTimeToLive(long l) throws JMSException
+ {
+ checkPreConditions();
+ if (l < 0)
+ {
+ throw new IllegalArgumentException("Time to live must be non-negative - supplied value was " + l);
+ }
+
+ _timeToLive = l;
+ }
+
+ public long getTimeToLive() throws JMSException
+ {
+ checkNotClosed();
+
+ return _timeToLive;
+ }
+
+ public Destination getDestination() throws JMSException
+ {
+ checkNotClosed();
+
+ return _destination;
+ }
+
+ public void close() throws JMSException
+ {
+ _closed.set(true);
+ _session.deregisterProducer(_producerId);
+ }
+
+ public void send(Message message) throws JMSException
+ {
+ checkPreConditions();
+ checkInitialDestination();
+
+ synchronized (_connection.getFailoverMutex())
+ {
+ sendImpl(_destination, message, _deliveryMode, _messagePriority, _timeToLive, _mandatory, _immediate);
+ }
+ }
+
+ public void send(Message message, int deliveryMode) throws JMSException
+ {
+ checkPreConditions();
+ checkInitialDestination();
+
+ synchronized (_connection.getFailoverMutex())
+ {
+ sendImpl(_destination, message, deliveryMode, _messagePriority, _timeToLive, _mandatory, _immediate);
+ }
+ }
+
+ public void send(Message message, int deliveryMode, boolean immediate) throws JMSException
+ {
+ checkPreConditions();
+ checkInitialDestination();
+ synchronized (_connection.getFailoverMutex())
+ {
+ sendImpl(_destination, message, deliveryMode, _messagePriority, _timeToLive, _mandatory, immediate);
+ }
+ }
+
+ public void send(Message message, int deliveryMode, int priority, long timeToLive) throws JMSException
+ {
+ checkPreConditions();
+ checkInitialDestination();
+ synchronized (_connection.getFailoverMutex())
+ {
+ sendImpl(_destination, message, deliveryMode, priority, timeToLive, _mandatory, _immediate);
+ }
+ }
+
+ public void send(Destination destination, Message message) throws JMSException
+ {
+ checkPreConditions();
+ checkDestination(destination);
+ synchronized (_connection.getFailoverMutex())
+ {
+ validateDestination(destination);
+ sendImpl((AMQDestination) destination, message, _deliveryMode, _messagePriority, _timeToLive, _mandatory,
+ _immediate);
+ }
+ }
+
+ public void send(Destination destination, Message message, int deliveryMode, int priority, long timeToLive)
+ throws JMSException
+ {
+ checkPreConditions();
+ checkDestination(destination);
+ synchronized (_connection.getFailoverMutex())
+ {
+ validateDestination(destination);
+ sendImpl((AMQDestination) destination, message, deliveryMode, priority, timeToLive, _mandatory, _immediate);
+ }
+ }
+
+ public void send(Destination destination, Message message, int deliveryMode, int priority, long timeToLive,
+ boolean mandatory) throws JMSException
+ {
+ checkPreConditions();
+ checkDestination(destination);
+ synchronized (_connection.getFailoverMutex())
+ {
+ validateDestination(destination);
+ sendImpl((AMQDestination) destination, message, deliveryMode, priority, timeToLive, mandatory, _immediate);
+ }
+ }
+
+ public void send(Destination destination, Message message, int deliveryMode, int priority, long timeToLive,
+ boolean mandatory, boolean immediate) throws JMSException
+ {
+ checkPreConditions();
+ checkDestination(destination);
+ synchronized (_connection.getFailoverMutex())
+ {
+ validateDestination(destination);
+ sendImpl((AMQDestination) destination, message, deliveryMode, priority, timeToLive, mandatory, immediate);
+ }
+ }
+
+ public void send(Destination destination, Message message, int deliveryMode, int priority, long timeToLive,
+ boolean mandatory, boolean immediate, boolean waitUntilSent) throws JMSException
+ {
+ checkPreConditions();
+ checkDestination(destination);
+ synchronized (_connection.getFailoverMutex())
+ {
+ validateDestination(destination);
+ sendImpl((AMQDestination) destination, message, deliveryMode, priority, timeToLive, mandatory, immediate,
+ waitUntilSent);
+ }
+ }
+
+ private AbstractJMSMessage convertToNativeMessage(Message message) throws JMSException
+ {
+ if (message instanceof AbstractJMSMessage)
+ {
+ return (AbstractJMSMessage) message;
+ }
+ else
+ {
+ AbstractJMSMessage newMessage;
+
+ if (message instanceof BytesMessage)
+ {
+ newMessage = new MessageConverter((BytesMessage) message).getConvertedMessage();
+ }
+ else if (message instanceof MapMessage)
+ {
+ newMessage = new MessageConverter((MapMessage) message).getConvertedMessage();
+ }
+ else if (message instanceof ObjectMessage)
+ {
+ newMessage = new MessageConverter((ObjectMessage) message).getConvertedMessage();
+ }
+ else if (message instanceof TextMessage)
+ {
+ newMessage = new MessageConverter((TextMessage) message).getConvertedMessage();
+ }
+ else if (message instanceof StreamMessage)
+ {
+ newMessage = new MessageConverter((StreamMessage) message).getConvertedMessage();
+ }
+ else
+ {
+ newMessage = new MessageConverter(message).getConvertedMessage();
+ }
+
+ if (newMessage != null)
+ {
+ return newMessage;
+ }
+ else
+ {
+ throw new JMSException("Unable to send message, due to class conversion error: "
+ + message.getClass().getName());
+ }
+ }
+ }
+
+ private void validateDestination(Destination destination) throws JMSException
+ {
+ if (!(destination instanceof AMQDestination))
+ {
+ throw new JMSException("Unsupported destination class: "
+ + ((destination != null) ? destination.getClass() : null));
+ }
+
+ declareDestination((AMQDestination) destination);
+ }
+
+ protected void sendImpl(AMQDestination destination, Message message, int deliveryMode, int priority, long timeToLive,
+ boolean mandatory, boolean immediate) throws JMSException
+ {
+ sendImpl(destination, message, deliveryMode, priority, timeToLive, mandatory, immediate, _waitUntilSent);
+ }
+
+ /**
+ * The caller of this method must hold the failover mutex.
+ *
+ * @param destination
+ * @param origMessage
+ * @param deliveryMode
+ * @param priority
+ * @param timeToLive
+ * @param mandatory
+ * @param immediate
+ * @throws JMSException
+ */
+ protected void sendImpl(AMQDestination destination, Message origMessage, int deliveryMode, int priority, long timeToLive,
+ boolean mandatory, boolean immediate, boolean wait) throws JMSException
+ {
+ checkTemporaryDestination(destination);
+ origMessage.setJMSDestination(destination);
+
+ AbstractJMSMessage message = convertToNativeMessage(origMessage);
+
+ if (_disableMessageId)
+ {
+ message.setJMSMessageID(null);
+ }
+ else
+ {
+ if (message.getJMSMessageID() == null)
+ {
+ message.setJMSMessageID(UUID.randomUUID().toString());
+ }
+ }
+
+ int type;
+ if (destination instanceof Topic)
+ {
+ type = AMQDestination.TOPIC_TYPE;
+ }
+ else if (destination instanceof Queue)
+ {
+ type = AMQDestination.QUEUE_TYPE;
+ }
+ else
+ {
+ type = AMQDestination.UNKNOWN_TYPE;
+ }
+
+ message.getJmsHeaders().setInteger(CustomJMSXProperty.JMS_QPID_DESTTYPE.getShortStringName(), type);
+
+ // AMQP version change: Hardwire the version to 0-8 (major=8, minor=0)
+ // TODO: Connect this to the session version obtained from ProtocolInitiation for this session.
+ // Be aware of possible changes to parameter order as versions change.
+ AMQFrame publishFrame =
+ BasicPublishBody.createAMQFrame(_channelId, _protocolHandler.getProtocolMajorVersion(),
+ _protocolHandler.getProtocolMinorVersion(), destination.getExchangeName(), // exchange
+ immediate, // immediate
+ mandatory, // mandatory
+ destination.getRoutingKey(), // routingKey
+ _session.getTicket()); // ticket
+
+ message.prepareForSending();
+ ByteBuffer payload = message.getData();
+ BasicContentHeaderProperties contentHeaderProperties = message.getContentHeaderProperties();
+
+ if (!_disableTimestamps)
+ {
+ final long currentTime = System.currentTimeMillis();
+ contentHeaderProperties.setTimestamp(currentTime);
+
+ if (timeToLive > 0)
+ {
+ contentHeaderProperties.setExpiration(currentTime + timeToLive);
+ }
+ else
+ {
+ contentHeaderProperties.setExpiration(0);
+ }
+ }
+
+ contentHeaderProperties.setDeliveryMode((byte) deliveryMode);
+ contentHeaderProperties.setPriority((byte) priority);
+
+ final int size = (payload != null) ? payload.limit() : 0;
+ final int contentBodyFrameCount = calculateContentBodyFrameCount(payload);
+ final AMQFrame[] frames = new AMQFrame[2 + contentBodyFrameCount];
+
+ if (payload != null)
+ {
+ createContentBodies(payload, frames, 2, _channelId);
+ }
+
+ if ((contentBodyFrameCount != 0) && _logger.isDebugEnabled())
+ {
+ _logger.debug("Sending content body frames to " + destination);
+ }
+
+ // weight argument of zero indicates no child content headers, just bodies
+ // AMQP version change: Hardwire the version to 0-8 (major=8, minor=0)
+ // TODO: Connect this to the session version obtained from ProtocolInitiation for this session.
+ AMQFrame contentHeaderFrame =
+ ContentHeaderBody.createAMQFrame(_channelId,
+ BasicConsumeBody.getClazz(_protocolHandler.getProtocolMajorVersion(),
+ _protocolHandler.getProtocolMinorVersion()), 0, contentHeaderProperties, size);
+ if (_logger.isDebugEnabled())
+ {
+ _logger.debug("Sending content header frame to " + destination);
+ }
+
+ frames[0] = publishFrame;
+ frames[1] = contentHeaderFrame;
+ CompositeAMQDataBlock compositeFrame = new CompositeAMQDataBlock(frames);
+ _protocolHandler.writeFrame(compositeFrame, wait);
+
+ if (message != origMessage)
+ {
+ _logger.debug("Updating original message");
+ origMessage.setJMSPriority(message.getJMSPriority());
+ origMessage.setJMSTimestamp(message.getJMSTimestamp());
+ _logger.debug("Setting JMSExpiration:" + message.getJMSExpiration());
+ origMessage.setJMSExpiration(message.getJMSExpiration());
+ origMessage.setJMSMessageID(message.getJMSMessageID());
+ }
+ }
+
+ private void checkTemporaryDestination(AMQDestination destination) throws JMSException
+ {
+ if (destination instanceof TemporaryDestination)
+ {
+ _logger.debug("destination is temporary destination");
+ TemporaryDestination tempDest = (TemporaryDestination) destination;
+ if (tempDest.getSession().isClosed())
+ {
+ _logger.debug("session is closed");
+ throw new JMSException("Session for temporary destination has been closed");
+ }
+
+ if (tempDest.isDeleted())
+ {
+ _logger.debug("destination is deleted");
+ throw new JMSException("Cannot send to a deleted temporary destination");
+ }
+ }
+ }
+
+ /**
+ * Create content bodies. This will split a large message into numerous bodies depending on the negotiated
+ * maximum frame size.
+ *
+ * @param payload
+ * @param frames
+ * @param offset
+ * @param channelId @return the array of content bodies
+ */
+ private void createContentBodies(ByteBuffer payload, AMQFrame[] frames, int offset, int channelId)
+ {
+
+ if (frames.length == (offset + 1))
+ {
+ frames[offset] = ContentBody.createAMQFrame(channelId, new ContentBody(payload));
+ }
+ else
+ {
+
+ final long framePayloadMax = _session.getAMQConnection().getMaximumFrameSize() - 1;
+ long remaining = payload.remaining();
+ for (int i = offset; i < frames.length; i++)
+ {
+ payload.position((int) framePayloadMax * (i - offset));
+ int length = (remaining >= framePayloadMax) ? (int) framePayloadMax : (int) remaining;
+ payload.limit(payload.position() + length);
+ frames[i] = ContentBody.createAMQFrame(channelId, new ContentBody(payload.slice()));
+
+ remaining -= length;
+ }
+ }
+
+ }
+
+ private int calculateContentBodyFrameCount(ByteBuffer payload)
+ {
+ // we substract one from the total frame maximum size to account for the end of frame marker in a body frame
+ // (0xCE byte).
+ int frameCount;
+ if ((payload == null) || (payload.remaining() == 0))
+ {
+ frameCount = 0;
+ }
+ else
+ {
+ int dataLength = payload.remaining();
+ final long framePayloadMax = _session.getAMQConnection().getMaximumFrameSize() - 1;
+ int lastFrame = ((dataLength % framePayloadMax) > 0) ? 1 : 0;
+ frameCount = (int) (dataLength / framePayloadMax) + lastFrame;
+ }
+
+ return frameCount;
+ }
+
+ public void setMimeType(String mimeType) throws JMSException
+ {
+ checkNotClosed();
+ _mimeType = mimeType;
+ }
+
+ public void setEncoding(String encoding) throws JMSException, UnsupportedEncodingException
+ {
+ checkNotClosed();
+ _encoding = encoding;
+ }
+
+ private void checkPreConditions() throws javax.jms.IllegalStateException, JMSException
+ {
+ checkNotClosed();
+
+ if ((_session == null) || _session.isClosed())
+ {
+ throw new javax.jms.IllegalStateException("Invalid Session");
+ }
+ }
+
+ private void checkInitialDestination()
+ {
+ if (_destination == null)
+ {
+ throw new UnsupportedOperationException("Destination is null");
+ }
+ }
+
+ private void checkDestination(Destination suppliedDestination) throws InvalidDestinationException
+ {
+ if ((_destination != null) && (suppliedDestination != null))
+ {
+ throw new UnsupportedOperationException(
+ "This message producer was created with a Destination, therefore you cannot use an unidentified Destination");
+ }
+
+ if (suppliedDestination == null)
+ {
+ throw new InvalidDestinationException("Supplied Destination was invalid");
+ }
+
+ }
+
+ public AMQSession getSession()
+ {
+ return _session;
+ }
+
+ public boolean isBound(AMQDestination destination) throws JMSException
+ {
+ return _session.isQueueBound(destination.getExchangeName(), null, destination.getRoutingKey());
+ }
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/client/Closeable.java b/Final/java/client/src/main/java/org/apache/qpid/client/Closeable.java
new file mode 100644
index 0000000000..7e119343a1
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/Closeable.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.client;
+
+import javax.jms.IllegalStateException;
+import javax.jms.JMSException;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * Captures the 'closed' state of an object, that is initially open, can be tested to see if it is closed, and provides
+ * a 'close' method to close it.
+ *
+ * <p/><table id="crc"><caption>CRC Card</caption>
+ * <tr><th> Responsibilities <th> Collaborations
+ * <tr><td> Mark an object as closed.
+ * <tr><td> Check if an object is closed.
+ * <tr><td> Raise a JMS exception if an object is closed.
+ * </table>
+ *
+ * @todo Might be better to make this an interface. This whole class doesn't really encapsulate a terribly neat
+ * piece of re-usable functionality. A simple interface defining a close method would suffice.
+ *
+ * @todo The convenience method {@link #checkNotClosed} is not that helpfull, what if the caller wants to do something
+ * other than throw an exception? It doesn't really represent a very usefull re-usable piece of code. Consider
+ * inlining it and dropping the method.
+ */
+public abstract class Closeable
+{
+ /**
+ * We use an atomic boolean so that we do not have to synchronized access to this flag. Synchronizing access to this
+ * flag would mean have a synchronized block in every method.
+ */
+ protected final AtomicBoolean _closed = new AtomicBoolean(false);
+
+ /**
+ * Checks if this is closed, and raises a JMSException if it is.
+ *
+ * @throws JMSException If this is closed.
+ */
+ protected void checkNotClosed() throws JMSException
+ {
+ if (isClosed())
+ {
+ throw new IllegalStateException("Object " + toString() + " has been closed");
+ }
+ }
+
+ /**
+ * Checks if this is closed.
+ *
+ * @return <tt>true</tt> if this is closed, <tt>false</tt> otherwise.
+ */
+ public boolean isClosed()
+ {
+ return _closed.get();
+ }
+
+ /**
+ * Closes this object.
+ *
+ * @throws JMSException If this cannot be closed for any reason.
+ */
+ public abstract void close() throws JMSException;
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/client/ConnectionTuneParameters.java b/Final/java/client/src/main/java/org/apache/qpid/client/ConnectionTuneParameters.java
new file mode 100644
index 0000000000..b1ec7216bc
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/ConnectionTuneParameters.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.client;
+
+public class ConnectionTuneParameters
+{
+ private long _frameMax;
+
+ private int _channelMax;
+
+ private int _heartbeat;
+
+ private long _txnLimit;
+
+ public long getFrameMax()
+ {
+ return _frameMax;
+ }
+
+ public void setFrameMax(long frameMax)
+ {
+ _frameMax = frameMax;
+ }
+
+ public int getChannelMax()
+ {
+ return _channelMax;
+ }
+
+ public void setChannelMax(int channelMax)
+ {
+ _channelMax = channelMax;
+ }
+
+ public int getHeartbeat()
+ {
+ return _heartbeat;
+ }
+
+ public void setHeartbeat(int hearbeat)
+ {
+ _heartbeat = hearbeat;
+ }
+
+ public long getTxnLimit()
+ {
+ return _txnLimit;
+ }
+
+ public void setTxnLimit(long txnLimit)
+ {
+ _txnLimit = txnLimit;
+ }
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/client/CustomJMSXProperty.java b/Final/java/client/src/main/java/org/apache/qpid/client/CustomJMSXProperty.java
new file mode 100644
index 0000000000..a5e89ef4fc
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/CustomJMSXProperty.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.client;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Enumeration;
+
+import org.apache.qpid.framing.AMQShortString;
+
+public enum CustomJMSXProperty
+{
+ JMS_AMQP_NULL,
+ JMS_QPID_DESTTYPE,
+ JMSXGroupID,
+ JMSXGroupSeq;
+
+
+ private final AMQShortString _nameAsShortString;
+
+ CustomJMSXProperty()
+ {
+ _nameAsShortString = new AMQShortString(toString());
+ }
+
+ public AMQShortString getShortStringName()
+ {
+ return _nameAsShortString;
+ }
+
+ private static Enumeration _names;
+
+ public static synchronized Enumeration asEnumeration()
+ {
+ if(_names == null)
+ {
+ CustomJMSXProperty[] properties = values();
+ ArrayList<String> nameList = new ArrayList<String>(properties.length);
+ for(CustomJMSXProperty property : properties)
+ {
+ nameList.add(property.toString());
+ }
+ _names = Collections.enumeration(nameList);
+ }
+ return _names;
+ }
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/client/DispatcherCallback.java b/Final/java/client/src/main/java/org/apache/qpid/client/DispatcherCallback.java
new file mode 100644
index 0000000000..81a55006ed
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/DispatcherCallback.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.client;
+
+import java.util.Queue;
+
+public abstract class DispatcherCallback
+{
+ BasicMessageConsumer _consumer;
+
+ public DispatcherCallback(BasicMessageConsumer mc)
+ {
+ _consumer = mc;
+ }
+
+ abstract public void whilePaused(Queue<MessageConsumerPair> reprocessQueue);
+
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/client/JMSAMQException.java b/Final/java/client/src/main/java/org/apache/qpid/client/JMSAMQException.java
new file mode 100644
index 0000000000..0927ca3625
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/JMSAMQException.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.client;
+
+import org.apache.qpid.AMQException;
+
+import javax.jms.JMSException;
+
+/**
+ * JMSException does not accept wrapped exceptions in its constructor. Presumably this is because it is a relatively old
+ * Java exception class, before this was added as a default to Throwable. This exception class accepts wrapped exceptions
+ * as well as error messages, through its constructor, but is a JMSException.
+ *
+ * <p/><table id="crc"><caption>CRC Card</caption>
+ * <tr><th> Responsibilities <th> Collaborations
+ * <tr><td> Accept wrapped exceptions as a JMSException.
+ * </table>
+ */
+public class JMSAMQException extends JMSException
+{
+ /**
+ * Creates a JMSException, wrapping another exception class.
+ *
+ * @param message The error message.
+ * @param cause The underlying exception that caused this one. May be null if none is to be set.
+ */
+ public JMSAMQException(String message, Exception cause)
+ {
+ super(message);
+
+ if (cause != null)
+ {
+ setLinkedException(cause);
+ }
+ }
+
+ /**
+ * @param s The underlying exception.
+ *
+ * @deprecated Use the other constructor and write a helpfull message. This one will be deleted.
+ */
+ public JMSAMQException(AMQException s)
+ {
+ super(s.getMessage(), String.valueOf(s.getErrorCode()));
+ setLinkedException(s);
+ }
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/client/JmsNotImplementedException.java b/Final/java/client/src/main/java/org/apache/qpid/client/JmsNotImplementedException.java
new file mode 100644
index 0000000000..903514c35f
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/JmsNotImplementedException.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.client;
+
+import javax.jms.JMSException;
+
+public class JmsNotImplementedException extends JMSException
+{
+ public JmsNotImplementedException()
+ {
+ super("Not implemented");
+ }
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/client/MessageConsumerPair.java b/Final/java/client/src/main/java/org/apache/qpid/client/MessageConsumerPair.java
new file mode 100644
index 0000000000..585d6db3fd
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/MessageConsumerPair.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.client;
+
+public class MessageConsumerPair
+{
+ BasicMessageConsumer _consumer;
+ Object _item;
+
+ public MessageConsumerPair(BasicMessageConsumer consumer, Object item)
+ {
+ _consumer = consumer;
+ _item = item;
+ }
+
+ public BasicMessageConsumer getConsumer()
+ {
+ return _consumer;
+ }
+
+ public Object getItem()
+ {
+ return _item;
+ }
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/client/QpidConnectionMetaData.java b/Final/java/client/src/main/java/org/apache/qpid/client/QpidConnectionMetaData.java
new file mode 100644
index 0000000000..3bb5707417
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/QpidConnectionMetaData.java
@@ -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.
+ *
+ */
+package org.apache.qpid.client;
+
+import java.util.Enumeration;
+
+import javax.jms.ConnectionMetaData;
+import javax.jms.JMSException;
+
+import org.apache.qpid.common.QpidProperties;
+
+public class QpidConnectionMetaData implements ConnectionMetaData
+{
+
+
+ QpidConnectionMetaData(AMQConnection conn)
+ {
+ }
+
+ public int getJMSMajorVersion() throws JMSException
+ {
+ return 1;
+ }
+
+ public int getJMSMinorVersion() throws JMSException
+ {
+ return 1;
+ }
+
+ public String getJMSProviderName() throws JMSException
+ {
+ return "Apache " + QpidProperties.getProductName();
+ }
+
+ public String getJMSVersion() throws JMSException
+ {
+ return "1.1";
+ }
+
+ public Enumeration getJMSXPropertyNames() throws JMSException
+ {
+ return CustomJMSXProperty.asEnumeration();
+ }
+
+ public int getProviderMajorVersion() throws JMSException
+ {
+ return 0;
+ }
+
+ public int getProviderMinorVersion() throws JMSException
+ {
+ return 8;
+ }
+
+ public String getProviderVersion() throws JMSException
+ {
+ return QpidProperties.getProductName() + " (Client: [" + getClientVersion() + "] ; Broker [" + getBrokerVersion() + "] ; Protocol: [ "
+ + getProtocolVersion() + "] )";
+ }
+
+ private String getProtocolVersion()
+ {
+ // TODO - Implement based on connection negotiated protocol
+ return "0.8";
+ }
+
+ public String getBrokerVersion()
+ {
+ // TODO - get broker version
+ return "<unkown>";
+ }
+
+ public String getClientVersion()
+ {
+ return QpidProperties.getBuildVersion();
+ }
+
+
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/client/QueueReceiverAdaptor.java b/Final/java/client/src/main/java/org/apache/qpid/client/QueueReceiverAdaptor.java
new file mode 100644
index 0000000000..7059588367
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/QueueReceiverAdaptor.java
@@ -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.
+ *
+ */
+package org.apache.qpid.client;
+
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageListener;
+import javax.jms.Queue;
+import javax.jms.QueueReceiver;
+
+/**
+ * Class that wraps a MessageConsumer for backwards JMS compatibility
+ * Returned by methods in AMQSession etc
+ */
+public class QueueReceiverAdaptor implements QueueReceiver {
+
+ protected MessageConsumer _consumer;
+ protected Queue _queue;
+
+ protected QueueReceiverAdaptor(Queue queue, MessageConsumer consumer)
+ {
+ _consumer = consumer;
+ _queue = queue;
+ }
+
+ public String getMessageSelector() throws JMSException
+ {
+ checkPreConditions();
+ return _consumer.getMessageSelector();
+ }
+
+ public MessageListener getMessageListener() throws JMSException
+ {
+ checkPreConditions();
+ return _consumer.getMessageListener();
+ }
+
+ public void setMessageListener(MessageListener messageListener) throws JMSException
+ {
+ checkPreConditions();
+ _consumer.setMessageListener(messageListener);
+ }
+
+ public Message receive() throws JMSException
+ {
+ checkPreConditions();
+ return _consumer.receive();
+ }
+
+ public Message receive(long l) throws JMSException
+ {
+ checkPreConditions();
+ return _consumer.receive(l);
+ }
+
+ public Message receiveNoWait() throws JMSException
+ {
+ checkPreConditions();
+ return _consumer.receiveNoWait();
+ }
+
+ public void close() throws JMSException
+ {
+ _consumer.close();
+ }
+
+ /**
+ * Return the queue associated with this receiver
+ * @return
+ * @throws JMSException
+ */
+ public Queue getQueue() throws JMSException
+ {
+ checkPreConditions();
+ return _queue;
+ }
+
+ private void checkPreConditions() throws javax.jms.IllegalStateException {
+ BasicMessageConsumer msgConsumer = (BasicMessageConsumer)_consumer;
+
+ if (msgConsumer.isClosed() ){
+ throw new javax.jms.IllegalStateException("Consumer is closed");
+ }
+
+ if(_queue == null){
+ throw new UnsupportedOperationException("Queue is null");
+ }
+
+ AMQSession session = msgConsumer.getSession();
+
+ if(session == null || session.isClosed()){
+ throw new javax.jms.IllegalStateException("Invalid Session");
+ }
+ }
+
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/client/QueueSenderAdapter.java b/Final/java/client/src/main/java/org/apache/qpid/client/QueueSenderAdapter.java
new file mode 100644
index 0000000000..493e2b5ec0
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/QueueSenderAdapter.java
@@ -0,0 +1,230 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ *
+ */
+
+package org.apache.qpid.client;
+
+import javax.jms.Destination;
+import javax.jms.IllegalStateException;
+import javax.jms.InvalidDestinationException;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageProducer;
+import javax.jms.Queue;
+import javax.jms.QueueSender;
+
+public class QueueSenderAdapter implements QueueSender
+{
+
+ private BasicMessageProducer _delegate;
+ private Queue _queue;
+ private boolean closed = false;
+
+ public QueueSenderAdapter(BasicMessageProducer msgProducer, Queue queue)
+ {
+ _delegate = msgProducer;
+ _queue = queue;
+ }
+
+ public Queue getQueue() throws JMSException
+ {
+ checkPreConditions();
+
+ return _queue;
+ }
+
+ public void send(Message msg) throws JMSException
+ {
+ checkPreConditions();
+ _delegate.send(msg);
+ }
+
+ public void send(Queue queue, Message msg) throws JMSException
+ {
+ checkPreConditions(queue);
+ _delegate.send(queue, msg);
+ }
+
+ public void publish(Message msg, int deliveryMode, int priority, long timeToLive) throws JMSException
+ {
+ checkPreConditions();
+ _delegate.send(msg, deliveryMode, priority, timeToLive);
+ }
+
+ public void send(Queue queue, Message msg, int deliveryMode, int priority, long timeToLive) throws JMSException
+ {
+ checkPreConditions(queue);
+ _delegate.send(queue, msg, deliveryMode, priority, timeToLive);
+ }
+
+ public void close() throws JMSException
+ {
+ _delegate.close();
+ closed = true;
+ }
+
+ public int getDeliveryMode() throws JMSException
+ {
+ checkPreConditions();
+
+ return _delegate.getDeliveryMode();
+ }
+
+ public Destination getDestination() throws JMSException
+ {
+ checkPreConditions();
+
+ return _delegate.getDestination();
+ }
+
+ public boolean getDisableMessageID() throws JMSException
+ {
+ checkPreConditions();
+
+ return _delegate.getDisableMessageID();
+ }
+
+ public boolean getDisableMessageTimestamp() throws JMSException
+ {
+ checkPreConditions();
+
+ return _delegate.getDisableMessageTimestamp();
+ }
+
+ public int getPriority() throws JMSException
+ {
+ checkPreConditions();
+
+ return _delegate.getPriority();
+ }
+
+ public long getTimeToLive() throws JMSException
+ {
+ checkPreConditions();
+
+ return _delegate.getTimeToLive();
+ }
+
+ public void send(Destination dest, Message msg) throws JMSException
+ {
+ checkPreConditions((Queue) dest);
+ _delegate.send(dest, msg);
+ }
+
+ public void send(Message msg, int deliveryMode, int priority, long timeToLive) throws JMSException
+ {
+ checkPreConditions();
+ _delegate.send(msg, deliveryMode, priority, timeToLive);
+ }
+
+ public void send(Destination dest, Message msg, int deliveryMode, int priority, long timeToLive) throws JMSException
+ {
+ checkPreConditions((Queue) dest);
+ _delegate.send(dest, msg, deliveryMode, priority, timeToLive);
+ }
+
+ public void setDeliveryMode(int deliveryMode) throws JMSException
+ {
+ checkPreConditions();
+ _delegate.setDeliveryMode(deliveryMode);
+ }
+
+ public void setDisableMessageID(boolean disableMessageID) throws JMSException
+ {
+ checkPreConditions();
+ _delegate.setDisableMessageID(disableMessageID);
+ }
+
+ public void setDisableMessageTimestamp(boolean disableMessageTimestamp) throws JMSException
+ {
+ checkPreConditions();
+ _delegate.setDisableMessageTimestamp(disableMessageTimestamp);
+ }
+
+ public void setPriority(int priority) throws JMSException
+ {
+ checkPreConditions();
+ _delegate.setPriority(priority);
+ }
+
+ public void setTimeToLive(long timeToLive) throws JMSException
+ {
+ checkPreConditions();
+ _delegate.setTimeToLive(timeToLive);
+ }
+
+ private void checkPreConditions() throws JMSException
+ {
+ checkPreConditions(_queue);
+ }
+
+ private void checkPreConditions(Queue queue) throws JMSException
+ {
+ if (closed)
+ {
+ throw new javax.jms.IllegalStateException("Publisher is closed");
+ }
+
+ AMQSession session = ((BasicMessageProducer) _delegate).getSession();
+
+ if ((session == null) || session.isClosed())
+ {
+ throw new javax.jms.IllegalStateException("Invalid Session");
+ }
+
+ if (queue == null)
+ {
+ throw new UnsupportedOperationException("Queue is null.");
+ }
+
+ if (!(queue instanceof AMQDestination))
+ {
+ throw new InvalidDestinationException("Queue: " + queue + " is not a valid Qpid queue");
+ }
+
+ AMQDestination destination = (AMQDestination) queue;
+ if (!destination.isValidated() && checkQueueBeforePublish())
+ {
+
+ if (_delegate.getSession().isStrictAMQP())
+ {
+ _delegate._logger.warn("AMQP does not support destination validation before publish, ");
+ destination.setValidated(true);
+ }
+ else
+ {
+ if (_delegate.isBound(destination))
+ {
+ destination.setValidated(true);
+ }
+ else
+ {
+ throw new InvalidDestinationException("Queue: " + queue
+ + " is not a valid destination (no bindings on server");
+ }
+ }
+ }
+ }
+
+ private boolean checkQueueBeforePublish()
+ {
+ return "true".equalsIgnoreCase(System.getProperty("org.apache.qpid.client.verifyQueueBindingBeforePublish", "true"));
+ }
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/client/SSLConfiguration.java b/Final/java/client/src/main/java/org/apache/qpid/client/SSLConfiguration.java
new file mode 100644
index 0000000000..2280cc9870
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/SSLConfiguration.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.client;
+
+public class SSLConfiguration {
+
+ private String _keystorePath;
+
+ private String _keystorePassword;
+
+ private String _certType = "SunX509";
+
+ public void setKeystorePath(String path)
+ {
+ _keystorePath = path;
+ }
+
+ public String getKeystorePath()
+ {
+ return _keystorePath;
+ }
+
+ public void setKeystorePassword(String password)
+ {
+ _keystorePassword = password;
+ }
+
+ public String getKeystorePassword()
+ {
+ return _keystorePassword;
+ }
+
+ public void setCertType(String type)
+ {
+ _certType = type;
+ }
+
+ public String getCertType()
+ {
+ return _certType;
+ }
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/client/TemporaryDestination.java b/Final/java/client/src/main/java/org/apache/qpid/client/TemporaryDestination.java
new file mode 100644
index 0000000000..03d25aa243
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/TemporaryDestination.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.client;
+
+import javax.jms.Destination;
+import javax.jms.JMSException;
+
+/**
+ * Provides support for covenience interface implemented by both AMQTemporaryTopic and AMQTemporaryQueue
+ * so that operations related to their "temporary-ness" can be abstracted out.
+ */
+interface TemporaryDestination extends Destination
+{
+
+ public void delete() throws JMSException;
+ public AMQSession getSession();
+ public boolean isDeleted();
+
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/client/TopicPublisherAdapter.java b/Final/java/client/src/main/java/org/apache/qpid/client/TopicPublisherAdapter.java
new file mode 100644
index 0000000000..81b9940ed5
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/TopicPublisherAdapter.java
@@ -0,0 +1,205 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ *
+ */
+
+package org.apache.qpid.client;
+
+import javax.jms.Destination;
+import javax.jms.IllegalStateException;
+import javax.jms.InvalidDestinationException;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.Topic;
+import javax.jms.TopicPublisher;
+
+public class TopicPublisherAdapter implements TopicPublisher
+{
+
+ private BasicMessageProducer _delegate;
+ private Topic _topic;
+
+ public TopicPublisherAdapter(BasicMessageProducer msgProducer, Topic topic)
+ {
+ _delegate = msgProducer;
+ _topic = topic;
+ }
+
+ public Topic getTopic() throws JMSException
+ {
+ checkPreConditions();
+ return _topic;
+ }
+
+ public void publish(Message msg) throws JMSException
+ {
+ checkPreConditions();
+ checkTopic(_topic);
+ _delegate.send(msg);
+ }
+
+ public void publish(Topic topic, Message msg) throws JMSException
+ {
+ checkPreConditions();
+ checkTopic(topic);
+ _delegate.send(topic, msg);
+ }
+
+ public void publish(Message msg, int deliveryMode, int priority, long timeToLive)
+ throws JMSException
+ {
+ checkPreConditions();
+ checkTopic(_topic);
+ _delegate.send(msg, deliveryMode, priority, timeToLive);
+ }
+
+ public int getDeliveryMode() throws JMSException {
+ checkPreConditions();
+ return _delegate.getDeliveryMode();
+ }
+
+ public void publish(Topic topic, Message msg, int deliveryMode, int priority, long timeToLive)
+ throws JMSException
+ {
+ checkPreConditions();
+ checkTopic(topic);
+ _delegate.send(topic, msg, deliveryMode, priority, timeToLive);
+ }
+
+ public void close() throws JMSException
+ {
+ _delegate.close();
+ }
+
+ public boolean getDisableMessageID() throws JMSException {
+ checkPreConditions();
+ return _delegate.getDisableMessageID();
+ }
+
+ public boolean getDisableMessageTimestamp() throws JMSException {
+ checkPreConditions();
+ return _delegate.getDisableMessageTimestamp();
+ }
+
+ public Destination getDestination() throws JMSException
+ {
+ checkPreConditions();
+ return _delegate.getDestination();
+ }
+
+ public int getPriority() throws JMSException {
+ checkPreConditions();
+ return _delegate.getPriority();
+ }
+
+ public long getTimeToLive() throws JMSException {
+ checkPreConditions();
+ return _delegate.getTimeToLive();
+ }
+
+ public void send(Message msg) throws JMSException
+ {
+ checkPreConditions();
+ checkTopic(_topic);
+ _delegate.send(msg);
+ }
+
+ public void send(Destination dest, Message msg) throws JMSException
+ {
+ checkPreConditions();
+ checkTopic(_topic);
+ _delegate.send(dest, msg);
+ }
+
+ public void send(Message msg, int deliveryMode, int priority, long timeToLive)
+ throws JMSException
+ {
+ checkPreConditions();
+ checkTopic(_topic);
+ _delegate.send(msg, deliveryMode, priority, timeToLive);
+ }
+
+ public void send(Destination dest, Message msg, int deliveryMode, int priority, long timeToLive) throws JMSException
+ {
+ checkPreConditions();
+ checkTopic(dest);
+ _delegate.send(dest, msg, deliveryMode, priority, timeToLive);
+ }
+
+ public void setDeliveryMode(int deliveryMode) throws JMSException
+ {
+ checkPreConditions();
+ _delegate.setDeliveryMode(deliveryMode);
+ }
+
+ public void setDisableMessageID(boolean disableMessageID) throws JMSException
+ {
+ checkPreConditions();
+ _delegate.setDisableMessageID(disableMessageID);
+ }
+
+ public void setDisableMessageTimestamp(boolean disableMessageTimestamp) throws JMSException
+ {
+ checkPreConditions();
+ _delegate.setDisableMessageTimestamp(disableMessageTimestamp);
+ }
+
+ public void setPriority(int priority) throws JMSException
+ {
+ checkPreConditions();
+ _delegate.setPriority(priority);
+ }
+
+ public void setTimeToLive(long timeToLive) throws JMSException
+ {
+ checkPreConditions();
+ _delegate.setTimeToLive(timeToLive);
+ }
+
+ private void checkPreConditions() throws IllegalStateException
+ {
+ if (_delegate.isClosed())
+ {
+ throw new javax.jms.IllegalStateException("Publisher is _closed");
+ }
+
+ AMQSession session = _delegate.getSession();
+ if (session == null || session.isClosed())
+ {
+ throw new javax.jms.IllegalStateException("Invalid Session");
+ }
+ }
+
+ private void checkTopic(Destination topic) throws InvalidDestinationException
+ {
+ if (topic == null)
+ {
+ throw new UnsupportedOperationException("Topic is null");
+ }
+ if (!(topic instanceof Topic))
+ {
+ throw new InvalidDestinationException("Destination " + topic + " is not a topic");
+ }
+ if(!(topic instanceof AMQDestination))
+ {
+ throw new InvalidDestinationException("Destination " + topic + " is not a Qpid topic");
+ }
+
+ }
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/client/TopicSubscriberAdaptor.java b/Final/java/client/src/main/java/org/apache/qpid/client/TopicSubscriberAdaptor.java
new file mode 100644
index 0000000000..d4bec5d906
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/TopicSubscriberAdaptor.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.client;
+
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageListener;
+import javax.jms.Topic;
+import javax.jms.TopicSubscriber;
+
+/**
+ * Wraps a MessageConsumer to fulfill the extended TopicSubscriber contract
+ *
+ */
+class TopicSubscriberAdaptor implements TopicSubscriber
+{
+ private final Topic _topic;
+ private final BasicMessageConsumer _consumer;
+ private final boolean _noLocal;
+
+ TopicSubscriberAdaptor(Topic topic, BasicMessageConsumer consumer, boolean noLocal)
+ {
+ _topic = topic;
+ _consumer = consumer;
+ _noLocal = noLocal;
+ }
+
+ TopicSubscriberAdaptor(Topic topic, BasicMessageConsumer consumer)
+ {
+ this(topic, consumer, consumer.isNoLocal());
+ }
+
+ public Topic getTopic() throws JMSException
+ {
+ checkPreConditions();
+ return _topic;
+ }
+
+ public boolean getNoLocal() throws JMSException
+ {
+ checkPreConditions();
+ return _noLocal;
+ }
+
+ public String getMessageSelector() throws JMSException
+ {
+ checkPreConditions();
+ return _consumer.getMessageSelector();
+ }
+
+ public MessageListener getMessageListener() throws JMSException
+ {
+ checkPreConditions();
+ return _consumer.getMessageListener();
+ }
+
+ public void setMessageListener(MessageListener messageListener) throws JMSException
+ {
+ checkPreConditions();
+ _consumer.setMessageListener(messageListener);
+ }
+
+ public Message receive() throws JMSException
+ {
+ checkPreConditions();
+ return _consumer.receive();
+ }
+
+ public Message receive(long l) throws JMSException
+ {
+ return _consumer.receive(l);
+ }
+
+ public Message receiveNoWait() throws JMSException
+ {
+ checkPreConditions();
+ return _consumer.receiveNoWait();
+ }
+
+ public void close() throws JMSException
+ {
+ _consumer.close();
+ }
+
+ private void checkPreConditions() throws javax.jms.IllegalStateException{
+ BasicMessageConsumer msgConsumer = (BasicMessageConsumer)_consumer;
+
+ if (msgConsumer.isClosed() ){
+ throw new javax.jms.IllegalStateException("Consumer is closed");
+ }
+
+ if(_topic == null){
+ throw new UnsupportedOperationException("Topic is null");
+ }
+
+ AMQSession session = msgConsumer.getSession();
+
+ if(session == null || session.isClosed()){
+ throw new javax.jms.IllegalStateException("Invalid Session");
+ }
+ }
+
+ BasicMessageConsumer getMessageConsumer()
+ {
+ return _consumer;
+ }
+
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/client/failover/FailoverException.java b/Final/java/client/src/main/java/org/apache/qpid/client/failover/FailoverException.java
new file mode 100644
index 0000000000..037b0dc2d1
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/failover/FailoverException.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.client.failover;
+
+/**
+ * FailoverException is used to indicate that a synchronous request has failed to receive the reply that it is waiting
+ * for because the fail-over process has been started whilst it was waiting for its reply. Synchronous methods generally
+ * raise this exception to indicate that they must be re-tried once the fail-over process has completed.
+ *
+ * <p/><table id="crc"><caption>CRC Card</caption>
+ * <tr><th> Responsibilities <th> Collaborations
+ * <tr><td> Used to indicate failure of a synchronous request due to fail-over.
+ * </table>
+ *
+ * @todo This exception is created and passed as an argument to a method, rather than thrown. The exception is being
+ * used to represent an event, passed out to other threads. Use of exceptions as arguments rather than as
+ * exceptions is extremly confusing. Ideally use a condition or set a flag and check it instead.
+ * This exceptions-as-events pattern seems to be in a similar style to Mina code, which is not pretty, but
+ * potentially acceptable for that reason. We have the option of extending the mina model to add more events
+ * to it, that is, anything that is interested in handling failover as an event occurs below the main
+ * amq event handler, which knows the specific interface of the qpid handlers, which can pass this down as
+ * an explicit event, without it being an exception. Add failover method to BlockingMethodFrameListener,
+ * have it set a flag or interrupt the waiting thread, which then creates and raises this exception.
+ */
+public class FailoverException extends Exception
+{
+ public FailoverException(String message)
+ {
+ super(message);
+ }
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/client/failover/FailoverHandler.java b/Final/java/client/src/main/java/org/apache/qpid/client/failover/FailoverHandler.java
new file mode 100644
index 0000000000..5303993331
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/failover/FailoverHandler.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.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.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.concurrent.CountDownLatch;
+
+/**
+ * FailoverHandler is a continuation that performs the failover procedure on a protocol session. As described in the
+ * class level comment for {@link AMQProtocolHandler}, a protocol connection can span many physical transport
+ * connections, failing over to a new connection if the transport connection fails. The procedure to establish a new
+ * connection is expressed as a continuation, in order that it may be run in a seperate thread to the i/o thread that
+ * detected the failure and is used to handle the communication to establish a new connection.
+ *
+ * </p>The reason this needs to be a separate thread is because this work cannot be done inside the i/o processor
+ * thread. The significant task is the connection setup which involves a protocol exchange until a particular state
+ * is achieved. This procedure waits until the state is achieved which would prevent the i/o thread doing the work
+ * it needs to do to achieve the new state.
+ *
+ * <p/>The failover procedure does the following:
+ *
+ * <ol>
+ * <li>Sets the failing over condition to true.</li>
+ * <li>Creates a {@link FailoverException} and gets the protocol connection handler to propagate this event to all
+ * interested parties.</li>
+ * <li>Takes the failover mutex on the protocol connection handler.</li>
+ * <li>Abandons the fail over if any of the interested parties vetoes it. The mutex is released and the condition
+ * reset.</li>
+ * <li>Creates a new {@link AMQStateManager} and re-established the connection through it.</li>
+ * <li>Informs the AMQConnection if the connection cannot be re-established.</li>
+ * <li>Recreates all sessions from the old connection to the new.</li>
+ * <li>Resets the failing over condition and releases the mutex.</li>
+ * </ol>
+ *
+ * <p/><table id="crc"><caption>CRC Card</caption>
+ * <tr><th> Responsibilities <th> Collaborations
+ * <tr><td> Update fail-over state <td> {@link AMQProtocolHandler}
+ * </table>
+ *
+ * @todo The failover latch and mutex are used like a lock and condition. If the retrotranlator supports lock/condition
+ * then could change over to using them. 1.4 support still needed.
+ *
+ * @todo If the condition is set to null on a vetoes fail-over and there are already other threads waiting on the
+ * condition, they will never be released. It might be an idea to reset the condition in a finally block.
+ *
+ * @todo Creates a {@link AMQDisconnectedException} and passes it to the AMQConnection. No need to use an
+ * exception-as-argument here, could just as easily call a specific method for this purpose on AMQConnection.
+ *
+ * @todo Creates a {@link FailoverException} and propagates it to the MethodHandlers. No need to use an
+ * exception-as-argument here, could just as easily call a specific method for this purpose on
+ * {@link org.apache.qpid.protocol.AMQMethodListener}.
+ */
+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;
+
+ /** Used to hold the host to fail over to. This is optional and if not set a reconnect to the previous host is tried. */
+ private String _host;
+
+ /** Used to hold the port to fail over to. */
+ private int _port;
+
+ /**
+ * 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)
+ {
+ _amqProtocolHandler = amqProtocolHandler;
+ _session = session;
+ }
+
+ /**
+ * Performs the failover procedure. See the class level comment, {@link FailoverHandler}, for a description of the
+ * failover procedure.
+ */
+ public void run()
+ {
+ if (Thread.currentThread().isDaemon())
+ {
+ throw new IllegalStateException("FailoverHandler must run on a non-daemon thread.");
+ }
+
+ // Create a latch, upon which tasks that must not run in parallel with a failover can wait for completion of
+ // the fail over.
+ _amqProtocolHandler.setFailoverLatch(new CountDownLatch(1));
+
+ // We wake up listeners. If they can handle failover, they will extend the
+ // FailoverRetrySupport class and will in turn block on the latch until failover
+ // has completed before retrying the operation.
+ _amqProtocolHandler.propagateExceptionToWaiters(new FailoverException("Failing over about to start"));
+
+ // Since failover impacts several structures we protect them all with a single mutex. These structures
+ // are also in child objects of the connection. This allows us to manipulate them without affecting
+ // client code which runs in a separate thread.
+ synchronized (_amqProtocolHandler.getConnection().getFailoverMutex())
+ {
+ // We switch in a new state manager temporarily so that the interaction to get to the "connection open"
+ // state works, without us having to terminate any existing "state waiters". We could theoretically
+ // have a state waiter waiting until the connection is closed for some reason. Or in future we may have
+ // a slightly more complex state model therefore I felt it was worthwhile doing this.
+ AMQStateManager existingStateManager = _amqProtocolHandler.getStateManager();
+ _amqProtocolHandler.setStateManager(new AMQStateManager(_amqProtocolHandler.getProtocolSession()));
+ if (!_amqProtocolHandler.getConnection().firePreFailover(_host != null))
+ {
+ _logger.info("Failover process veto-ed by client");
+
+ _amqProtocolHandler.setStateManager(existingStateManager);
+ if (_host != null)
+ {
+ _amqProtocolHandler.getConnection().exceptionReceived(new AMQDisconnectedException(
+ "Redirect was vetoed by client"));
+ }
+ else
+ {
+ _amqProtocolHandler.getConnection().exceptionReceived(new AMQDisconnectedException(
+ "Failover was vetoed by client"));
+ }
+
+ _amqProtocolHandler.getFailoverLatch().countDown();
+ _amqProtocolHandler.setFailoverLatch(null);
+
+ return;
+ }
+
+ _logger.info("Starting failover process");
+
+ boolean failoverSucceeded;
+ // when host is non null we have a specified failover host otherwise we all the client to cycle through
+ // all specified hosts
+
+ // if _host has value then we are performing a redirect.
+ if (_host != null)
+ {
+ failoverSucceeded = _amqProtocolHandler.getConnection().attemptReconnection(_host, _port);
+ }
+ else
+ {
+ failoverSucceeded = _amqProtocolHandler.getConnection().attemptReconnection();
+ }
+
+ if (!failoverSucceeded)
+ {
+ _amqProtocolHandler.setStateManager(existingStateManager);
+ _amqProtocolHandler.getConnection().exceptionReceived(new AMQDisconnectedException(
+ "Server closed connection and no failover " + "was successful"));
+ }
+ else
+ {
+ _amqProtocolHandler.setStateManager(existingStateManager);
+ try
+ {
+ if (_amqProtocolHandler.getConnection().firePreResubscribe())
+ {
+ _logger.info("Resubscribing on new connection");
+ _amqProtocolHandler.getConnection().resubscribeSessions();
+ }
+ else
+ {
+ _logger.info("Client vetoed automatic resubscription");
+ }
+
+ _amqProtocolHandler.getConnection().fireFailoverComplete();
+ _amqProtocolHandler.setFailoverState(FailoverState.NOT_STARTED);
+ _logger.info("Connection failover completed successfully");
+ }
+ catch (Exception e)
+ {
+ _logger.info("Failover process failed - exception being propagated by protocol handler");
+ _amqProtocolHandler.setFailoverState(FailoverState.FAILED);
+ /*try
+ {*/
+ _amqProtocolHandler.exceptionCaught(_session, e);
+ /*}
+ catch (Exception ex)
+ {
+ _logger.error("Error notifying protocol session of error: " + ex, ex);
+ }*/
+ }
+ }
+ }
+
+ _amqProtocolHandler.getFailoverLatch().countDown();
+ }
+
+ /**
+ * Sets the host name to fail over to. This is optional and if not set a reconnect to the previous host is tried.
+ *
+ * @param host The host name to fail over to.
+ */
+ public void setHost(String host)
+ {
+ _host = host;
+ }
+
+ /**
+ * Sets the port to fail over to.
+ *
+ * @param port The port to fail over to.
+ */
+ public void setPort(int port)
+ {
+ _port = port;
+ }
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/client/failover/FailoverNoopSupport.java b/Final/java/client/src/main/java/org/apache/qpid/client/failover/FailoverNoopSupport.java
new file mode 100644
index 0000000000..1ec98efe0e
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/failover/FailoverNoopSupport.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.client.failover;
+
+import org.apache.qpid.client.AMQConnection;
+
+/**
+ * FailoverNoopSupport is a {@link FailoverSupport} implementation that does not really provide any failover support
+ * at all. It wraps a {@link FailoverProtectedOperation} but should that operation throw {@link FailoverException} this
+ * support class simply re-raises that exception as an IllegalStateException. This support wrapper should only be
+ * used where the caller can be certain that the failover protected operation cannot acutally throw a failover exception,
+ * for example, because the caller already holds a lock preventing that condition from arising.
+ *
+ * <p><table id="crc"><caption>CRC Card</caption>
+ * <tr><th> Responsibilities <th> Collaborations
+ * <tr><td> Perform a fail-over protected operation raising providing no handling of fail-over conditions.
+ * </table>
+ */
+public class FailoverNoopSupport<T, E extends Exception> implements FailoverSupport<T, E>
+{
+ /** The protected operation that is to be retried in the event of fail-over. */
+ FailoverProtectedOperation<T, E> operation;
+
+ /** The connection on which the fail-over protected operation is to be performed. */
+ AMQConnection connection;
+
+ /**
+ * Creates an automatic retrying fail-over handler for the specified operation.
+ *
+ * @param operation The fail-over protected operation to wrap in this handler.
+ */
+ public FailoverNoopSupport(FailoverProtectedOperation<T, E> operation, AMQConnection con)
+ {
+ this.operation = operation;
+ this.connection = con;
+ }
+
+ /**
+ * Delegates to another continuation which is to be provided with fail-over handling.
+ *
+ * @return The return value from the delegated to continuation.
+ * @throws E Any exception that the delegated to continuation may raise.
+ */
+ public T execute() throws E
+ {
+ try
+ {
+ return operation.execute();
+ }
+ catch (FailoverException e)
+ {
+ throw new IllegalStateException("Fail-over interupted no-op failover support. "
+ + "No-op support should only be used where the caller is certain fail-over cannot occur.", e);
+ }
+ }
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/client/failover/FailoverProtectedOperation.java b/Final/java/client/src/main/java/org/apache/qpid/client/failover/FailoverProtectedOperation.java
new file mode 100644
index 0000000000..9a7f43926e
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/failover/FailoverProtectedOperation.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.client.failover;
+
+/**
+ * FailoverProtectedOperation is a continuation for an operation that may throw a {@link FailoverException} because
+ * it has been interrupted by the fail-over process. The {@link FailoverRetrySupport} class defines support wrappers
+ * for failover protected operations, in order to provide different handling schemes when failovers occurr.
+ *
+ * <p/>The type of checked exception that the operation may perform has been generified, in order that fail over
+ * protected operations can be defined that raise arbitrary exceptions. The actuall exception types used should not
+ * be sub-classes of FailoverException, or else catching FailoverException in the {@link FailoverRetrySupport} classes
+ * will mask the exception.
+ *
+ * <p><table id="crc"><caption>CRC Card</caption>
+ * <tr><th> Responsibilities
+ * <tr><td> Perform an operation that may be interrupted by fail-over.
+ * </table>
+ */
+public interface FailoverProtectedOperation<T, E extends Exception>
+{
+ /**
+ * Performs the continuations work.
+ *
+ * @return Provdes scope for the continuation to return an arbitrary value.
+ *
+ * @throws FailoverException If the operation is interrupted by a fail-over notification.
+ */
+ public abstract T execute() throws E, FailoverException;
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/client/failover/FailoverRetrySupport.java b/Final/java/client/src/main/java/org/apache/qpid/client/failover/FailoverRetrySupport.java
new file mode 100644
index 0000000000..120a07f0fc
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/failover/FailoverRetrySupport.java
@@ -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.
+ *
+ */
+package org.apache.qpid.client.failover;
+
+import org.apache.qpid.client.AMQConnection;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * FailoverRetrySupport is a continuation that wraps another continuation, delaying its execution until it is notified
+ * that a blocking condition has been met, and executing the continuation within a mutex. If the continuation fails, due
+ * to the original condition being broken, whilst the continuation is waiting for a reponse to a synchronous request,
+ * FailoverRetrySupport automatcally rechecks the condition and re-acquires the mutex and re-runs the continution. This
+ * automatic retrying is continued until the continuation succeeds, or throws an exception (different to
+ * FailoverException, which is used to signal the failure of the original condition).
+ *
+ * <p/>The blocking condition used is that the connection is not currently failing over, and the mutex used is the
+ * connection failover mutex, which guards against the fail-over process being run during fail-over vulnerable methods.
+ * These are used like a lock and condition variable.
+ *
+ * <p/>The wrapped operation may throw a FailoverException, this is an exception that can be raised by a
+ * {@link org.apache.qpid.client.protocol.BlockingMethodFrameListener}, in response to it being notified that a
+ * fail-over wants to start whilst it was waiting. Methods that are vulnerable to fail-over are those that are
+ * synchronous, where a failure will prevent them from getting the reply they are waiting for and asynchronous
+ * methods that should not be attempted when a fail-over is in progress.
+ *
+ * <p/>Wrapping a synchronous method in a FailoverRetrySupport will have the effect that the operation will not be
+ * started during fail-over, but be delayed until any current fail-over has completed. Should a fail-over process want
+ * to start whilst waiting for the synchrnous reply, the FailoverRetrySupport will detect this and rety the operation
+ * until it succeeds. Synchronous methods are usually coordinated with a
+ * {@link org.apache.qpid.client.protocol.BlockingMethodFrameListener} which is notified when a fail-over process wants
+ * to start and throws a FailoverException in response to this.
+ *
+ * <p/>Wrapping an asynchronous method in a FailoverRetrySupport will have the effect that the operation will not be
+ * started during fail-over, but be delayed until any current fail-over has completed.
+ *
+ * <p/><table id="crc"><caption>CRC Card</caption>
+ * <tr><th> Responsibilities <th> Collaborations
+ * <tr><td> Provide a continuation synchronized on a fail-over lock and condition.
+ * <tr><td> Automatically retry the continuation accross fail-overs until it succeeds, or raises an exception.
+ * </table>
+ *
+ * @todo Another continuation. Could use an interface Continuation (as described in other todos, for example, see
+ * {@link org.apache.qpid.pool.Job}). Then have a wrapping continuation (this), which blocks on an arbitrary
+ * Condition or Latch (specified in constructor call), that this blocks on before calling the wrapped Continuation.
+ * Must work on Java 1.4, so check retrotranslator works on Lock/Condition or latch first. Argument and return type
+ * to match wrapped condition as type parameters. Rename to AsyncConditionalContinuation or something like that.
+ *
+ * @todo InterruptedException not handled well.
+ */
+public class FailoverRetrySupport<T, E extends Exception> implements FailoverSupport<T, E>
+{
+ /** Used for debugging. */
+ private static final Logger _log = LoggerFactory.getLogger(FailoverRetrySupport.class);
+
+ /** The protected operation that is to be retried in the event of fail-over. */
+ FailoverProtectedOperation<T, E> operation;
+
+ /** The connection on which the fail-over protected operation is to be performed. */
+ AMQConnection connection;
+
+ /**
+ * Creates an automatic retrying fail-over handler for the specified operation.
+ *
+ * @param operation The fail-over protected operation to wrap in this handler.
+ */
+ public FailoverRetrySupport(FailoverProtectedOperation<T, E> operation, AMQConnection con)
+ {
+ this.operation = operation;
+ this.connection = con;
+ }
+
+ /**
+ * Delays a continuation until the "not failing over" condition is met on the specified connection. Repeats
+ * until the operation throws AMQException or succeeds without being interrupted by fail-over.
+ *
+ * @return The result of executing the continuation.
+ *
+ * @throws E Any underlying exception is allowed to fall through.
+ */
+ 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);
+ }
+ }
+ }
+ }
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/client/failover/FailoverState.java b/Final/java/client/src/main/java/org/apache/qpid/client/failover/FailoverState.java
new file mode 100644
index 0000000000..807a5f7d13
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/failover/FailoverState.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.client.failover;
+
+/**
+ * Defines the possible states of the failover process; not started, in progress, failed.
+ *
+ * <p/><table id="crc"><caption>CRC Card</caption>
+ * <tr><th> Responsibilities <th> Collaborations
+ * <tr><td> Represent a one of the states of the fail-over process.
+ * </table>
+ */
+public final class FailoverState
+{
+ /** The string description on this state. */
+ private final String _state;
+
+ /** Failover has not yet been attempted on this connection. */
+ public static final FailoverState NOT_STARTED = new FailoverState("NOT STARTED");
+
+ /** Failover has been requested on this connection but has not completed. */
+ public static final FailoverState IN_PROGRESS = new FailoverState("IN PROGRESS");
+
+ /** Failover has been attempted and failed. */
+ public static final FailoverState FAILED = new FailoverState("FAILED");
+
+ /**
+ * Creates a type safe enumeration of a fail-over state.
+ *
+ * @param state The fail-over state description string.
+ */
+ private FailoverState(String state)
+ {
+ _state = state;
+ }
+
+ /**
+ * Prints this state, mainly for debugging purposes.
+ *
+ * @return The string description of this state.
+ */
+ public String toString()
+ {
+ return "FailoverState: " + _state;
+ }
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/client/failover/FailoverSupport.java b/Final/java/client/src/main/java/org/apache/qpid/client/failover/FailoverSupport.java
new file mode 100644
index 0000000000..ef2e7e1d65
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/failover/FailoverSupport.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.client.failover;
+
+/**
+ * FailoverSupport defines an interface for different types of fail-over handlers, that provide different types of
+ * behaviour for handling fail-overs during operations that can be interrupted by the fail-over process. For example,
+ * the support could automatically retry once the fail-over process completes, could prevent an operation from being
+ * started whilst fail-over is running, or could quietly abandon the operation or raise an exception, and so on.
+ *
+ * <p><table id="crc"><caption>CRC Card</caption>
+ * <tr><th> Responsibilities
+ * <tr><td> Perform a fail-over protected operation with handling for fail-over conditions.
+ * </table>
+ *
+ * @todo Continuation, extend some sort of re-usable Continuation interface, which might look very like this one.
+ */
+public interface FailoverSupport<T, E extends Exception>
+{
+ /**
+ * Delegates to another continuation which is to be provided with fail-over handling.
+ *
+ * @return The return value from the delegated to continuation.
+ *
+ * @throws E Any exception that the delegated to continuation may raise.
+ */
+ public T execute() throws E;
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/client/handler/BasicCancelOkMethodHandler.java b/Final/java/client/src/main/java/org/apache/qpid/client/handler/BasicCancelOkMethodHandler.java
new file mode 100644
index 0000000000..8f0ee05b3e
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/handler/BasicCancelOkMethodHandler.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.client.handler;
+
+import org.apache.qpid.AMQException;
+import org.apache.qpid.client.protocol.AMQProtocolSession;
+import org.apache.qpid.client.state.AMQStateManager;
+import org.apache.qpid.client.state.StateAwareMethodListener;
+import org.apache.qpid.framing.BasicCancelOkBody;
+import org.apache.qpid.protocol.AMQMethodEvent;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class BasicCancelOkMethodHandler implements StateAwareMethodListener
+{
+ private static final Logger _logger = LoggerFactory.getLogger(BasicCancelOkMethodHandler.class);
+
+ private static final BasicCancelOkMethodHandler _instance = new BasicCancelOkMethodHandler();
+
+ public static BasicCancelOkMethodHandler getInstance()
+ {
+ return _instance;
+ }
+
+ private BasicCancelOkMethodHandler()
+ { }
+
+ public void methodReceived(AMQStateManager stateManager, AMQProtocolSession protocolSession, AMQMethodEvent evt)
+ throws AMQException
+ {
+ BasicCancelOkBody body = (BasicCancelOkBody) evt.getMethod();
+
+ if (_logger.isInfoEnabled())
+ {
+ _logger.info("New BasicCancelOk method received for consumer:" + body.consumerTag);
+ }
+
+ protocolSession.confirmConsumerCancelled(evt.getChannelId(), body.consumerTag);
+ }
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/client/handler/BasicDeliverMethodHandler.java b/Final/java/client/src/main/java/org/apache/qpid/client/handler/BasicDeliverMethodHandler.java
new file mode 100644
index 0000000000..51120da55c
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/handler/BasicDeliverMethodHandler.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.client.handler;
+
+import org.apache.qpid.AMQException;
+import org.apache.qpid.client.message.UnprocessedMessage;
+import org.apache.qpid.client.protocol.AMQProtocolSession;
+import org.apache.qpid.client.state.AMQStateManager;
+import org.apache.qpid.client.state.StateAwareMethodListener;
+import org.apache.qpid.framing.BasicDeliverBody;
+import org.apache.qpid.protocol.AMQMethodEvent;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class BasicDeliverMethodHandler implements StateAwareMethodListener
+{
+ private static final Logger _logger = LoggerFactory.getLogger(BasicDeliverMethodHandler.class);
+
+ private static final BasicDeliverMethodHandler _instance = new BasicDeliverMethodHandler();
+
+ public static BasicDeliverMethodHandler getInstance()
+ {
+ return _instance;
+ }
+
+ public void methodReceived(AMQStateManager stateManager, AMQProtocolSession protocolSession, AMQMethodEvent evt)
+ throws AMQException
+ {
+ final UnprocessedMessage msg = new UnprocessedMessage(evt.getChannelId(), (BasicDeliverBody) evt.getMethod());
+ _logger.debug("New JmsDeliver method received");
+ protocolSession.unprocessedMessageReceived(msg);
+ }
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/client/handler/BasicReturnMethodHandler.java b/Final/java/client/src/main/java/org/apache/qpid/client/handler/BasicReturnMethodHandler.java
new file mode 100644
index 0000000000..0f00c6a26e
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/handler/BasicReturnMethodHandler.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.client.handler;
+
+import org.apache.qpid.AMQException;
+import org.apache.qpid.client.message.UnprocessedMessage;
+import org.apache.qpid.client.protocol.AMQProtocolSession;
+import org.apache.qpid.client.state.AMQStateManager;
+import org.apache.qpid.client.state.StateAwareMethodListener;
+import org.apache.qpid.framing.BasicReturnBody;
+import org.apache.qpid.protocol.AMQMethodEvent;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class BasicReturnMethodHandler implements StateAwareMethodListener
+{
+ private static final Logger _logger = LoggerFactory.getLogger(BasicReturnMethodHandler.class);
+
+ private static final BasicReturnMethodHandler _instance = new BasicReturnMethodHandler();
+
+ public static BasicReturnMethodHandler getInstance()
+ {
+ return _instance;
+ }
+
+ public void methodReceived(AMQStateManager stateManager, AMQProtocolSession protocolSession, AMQMethodEvent evt)
+ throws AMQException
+ {
+ _logger.debug("New JmsBounce method received");
+ final UnprocessedMessage msg = new UnprocessedMessage(evt.getChannelId(), (BasicReturnBody) evt.getMethod());
+
+ protocolSession.unprocessedMessageReceived(msg);
+ }
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/client/handler/ChannelCloseMethodHandler.java b/Final/java/client/src/main/java/org/apache/qpid/client/handler/ChannelCloseMethodHandler.java
new file mode 100644
index 0000000000..139a32370e
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/handler/ChannelCloseMethodHandler.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.client.handler;
+
+import org.apache.qpid.AMQChannelClosedException;
+import org.apache.qpid.AMQException;
+import org.apache.qpid.AMQInvalidRoutingKeyException;
+import org.apache.qpid.client.AMQNoConsumersException;
+import org.apache.qpid.client.AMQNoRouteException;
+import org.apache.qpid.client.protocol.AMQProtocolSession;
+import org.apache.qpid.client.state.AMQStateManager;
+import org.apache.qpid.client.state.StateAwareMethodListener;
+import org.apache.qpid.framing.AMQFrame;
+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.apache.qpid.protocol.AMQMethodEvent;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ChannelCloseMethodHandler implements StateAwareMethodListener
+{
+ private static final Logger _logger = LoggerFactory.getLogger(ChannelCloseMethodHandler.class);
+
+ private static ChannelCloseMethodHandler _handler = new ChannelCloseMethodHandler();
+
+ public static ChannelCloseMethodHandler getInstance()
+ {
+ return _handler;
+ }
+
+ public void methodReceived(AMQStateManager stateManager, AMQProtocolSession protocolSession, AMQMethodEvent evt)
+ throws AMQException
+ {
+ _logger.debug("ChannelClose method received");
+ ChannelCloseBody method = (ChannelCloseBody) evt.getMethod();
+
+ AMQConstant errorCode = AMQConstant.getConstant(method.replyCode);
+ AMQShortString reason = method.replyText;
+ if (_logger.isDebugEnabled())
+ {
+ _logger.debug("Channel close reply code: " + errorCode + ", reason: " + reason);
+ }
+
+ // TODO: Be aware of possible changes to parameter order as versions change.
+ AMQFrame frame = ChannelCloseOkBody.createAMQFrame(evt.getChannelId(), method.getMajor(), method.getMinor());
+ protocolSession.writeFrame(frame);
+ if (errorCode != AMQConstant.REPLY_SUCCESS)
+ {
+ 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);
+ }
+ else if (errorCode == AMQConstant.NO_ROUTE)
+ {
+ throw new AMQNoRouteException("Error: " + reason, null);
+ }
+ else if (errorCode == AMQConstant.INVALID_ARGUMENT)
+ {
+ _logger.debug("Broker responded with Invalid Argument.");
+
+ throw new org.apache.qpid.AMQInvalidArgumentException(String.valueOf(reason));
+ }
+ else if (errorCode == AMQConstant.INVALID_ROUTING_KEY)
+ {
+ _logger.debug("Broker responded with Invalid Routing Key.");
+
+ throw new AMQInvalidRoutingKeyException(String.valueOf(reason));
+ }
+ else
+ {
+ throw new AMQChannelClosedException(errorCode, "Error: " + reason);
+ }
+
+ }
+ // fixme why is this only done when the close is expected...
+ // should the above forced closes not also cause a close?
+ protocolSession.channelClosed(evt.getChannelId(), errorCode, String.valueOf(reason));
+ }
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/client/handler/ChannelCloseOkMethodHandler.java b/Final/java/client/src/main/java/org/apache/qpid/client/handler/ChannelCloseOkMethodHandler.java
new file mode 100644
index 0000000000..e1fe2697e5
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/handler/ChannelCloseOkMethodHandler.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.client.handler;
+
+import org.apache.qpid.AMQException;
+import org.apache.qpid.client.protocol.AMQProtocolSession;
+import org.apache.qpid.client.state.AMQStateManager;
+import org.apache.qpid.client.state.StateAwareMethodListener;
+import org.apache.qpid.protocol.AMQMethodEvent;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ChannelCloseOkMethodHandler implements StateAwareMethodListener
+{
+ private static final Logger _logger = LoggerFactory.getLogger(ChannelCloseOkMethodHandler.class);
+
+ private static final ChannelCloseOkMethodHandler _instance = new ChannelCloseOkMethodHandler();
+
+ public static ChannelCloseOkMethodHandler getInstance()
+ {
+ return _instance;
+ }
+
+ public void methodReceived(AMQStateManager stateManager, AMQProtocolSession protocolSession, AMQMethodEvent evt)
+ throws AMQException
+ {
+ _logger.info("Received channel-close-ok for channel-id " + evt.getChannelId());
+
+ // todo this should do the local closure
+ }
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/client/handler/ChannelFlowOkMethodHandler.java b/Final/java/client/src/main/java/org/apache/qpid/client/handler/ChannelFlowOkMethodHandler.java
new file mode 100644
index 0000000000..ca3f46d08b
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/handler/ChannelFlowOkMethodHandler.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.client.handler;
+
+import org.apache.qpid.AMQException;
+import org.apache.qpid.client.protocol.AMQProtocolSession;
+import org.apache.qpid.client.state.AMQStateManager;
+import org.apache.qpid.client.state.StateAwareMethodListener;
+import org.apache.qpid.framing.ChannelFlowOkBody;
+import org.apache.qpid.protocol.AMQMethodEvent;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ChannelFlowOkMethodHandler implements StateAwareMethodListener
+{
+ private static final Logger _logger = LoggerFactory.getLogger(ChannelFlowOkMethodHandler.class);
+ private static final ChannelFlowOkMethodHandler _instance = new ChannelFlowOkMethodHandler();
+
+ public static ChannelFlowOkMethodHandler getInstance()
+ {
+ return _instance;
+ }
+
+ private ChannelFlowOkMethodHandler()
+ { }
+
+ public void methodReceived(AMQStateManager stateManager, AMQProtocolSession protocolSession, AMQMethodEvent evt)
+ throws AMQException
+ {
+ ChannelFlowOkBody method = (ChannelFlowOkBody) evt.getMethod();
+ _logger.debug("Received Channel.Flow-Ok message, active = " + method.active);
+ }
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/client/handler/ConnectionCloseMethodHandler.java b/Final/java/client/src/main/java/org/apache/qpid/client/handler/ConnectionCloseMethodHandler.java
new file mode 100644
index 0000000000..df096d3c4e
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/handler/ConnectionCloseMethodHandler.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.client.handler;
+
+import org.apache.qpid.AMQConnectionClosedException;
+import org.apache.qpid.AMQException;
+import org.apache.qpid.client.AMQAuthenticationException;
+import org.apache.qpid.client.protocol.AMQProtocolSession;
+import org.apache.qpid.client.state.AMQState;
+import org.apache.qpid.client.state.AMQStateManager;
+import org.apache.qpid.client.state.StateAwareMethodListener;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.framing.ConnectionCloseBody;
+import org.apache.qpid.framing.ConnectionCloseOkBody;
+import org.apache.qpid.protocol.AMQConstant;
+import org.apache.qpid.protocol.AMQMethodEvent;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ConnectionCloseMethodHandler implements StateAwareMethodListener
+{
+ private static final Logger _logger = LoggerFactory.getLogger(ConnectionCloseMethodHandler.class);
+
+ private static ConnectionCloseMethodHandler _handler = new ConnectionCloseMethodHandler();
+
+ public static ConnectionCloseMethodHandler getInstance()
+ {
+ return _handler;
+ }
+
+ private ConnectionCloseMethodHandler()
+ { }
+
+ public void methodReceived(AMQStateManager stateManager, AMQProtocolSession protocolSession, AMQMethodEvent evt)
+ throws AMQException
+ {
+ _logger.info("ConnectionClose frame received");
+ ConnectionCloseBody method = (ConnectionCloseBody) evt.getMethod();
+
+ // does it matter
+ // stateManager.changeState(AMQState.CONNECTION_CLOSING);
+
+ AMQConstant errorCode = AMQConstant.getConstant(method.replyCode);
+ AMQShortString reason = method.replyText;
+
+ try
+ {
+ // TODO: check whether channel id of zero is appropriate
+ // Be aware of possible changes to parameter order as versions change.
+ protocolSession.writeFrame(ConnectionCloseOkBody.createAMQFrame((short) 0, method.getMajor(),
+ method.getMinor()));
+
+ if (errorCode != AMQConstant.REPLY_SUCCESS)
+ {
+ if (errorCode == AMQConstant.NOT_ALLOWED)
+ {
+ _logger.info("Authentication Error:" + Thread.currentThread().getName());
+
+ protocolSession.closeProtocolSession();
+
+ // todo this is a bit of a fudge (could be conssidered such as each new connection needs a new state manager or at least a fresh state.
+ stateManager.changeState(AMQState.CONNECTION_NOT_STARTED);
+
+ throw new AMQAuthenticationException(errorCode, (reason == null) ? null : reason.toString());
+ }
+ else
+ {
+ _logger.info("Connection close received with error code " + errorCode);
+
+ throw new AMQConnectionClosedException(errorCode, "Error: " + reason);
+ }
+ }
+ }
+ finally
+ {
+ // this actually closes the connection in the case where it is not an error.
+
+ protocolSession.closeProtocolSession();
+
+ stateManager.changeState(AMQState.CONNECTION_CLOSED);
+ }
+ }
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/client/handler/ConnectionOpenOkMethodHandler.java b/Final/java/client/src/main/java/org/apache/qpid/client/handler/ConnectionOpenOkMethodHandler.java
new file mode 100644
index 0000000000..2e0f273c32
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/handler/ConnectionOpenOkMethodHandler.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.client.handler;
+
+import org.apache.qpid.AMQException;
+import org.apache.qpid.client.protocol.AMQProtocolSession;
+import org.apache.qpid.client.state.AMQState;
+import org.apache.qpid.client.state.AMQStateManager;
+import org.apache.qpid.client.state.StateAwareMethodListener;
+import org.apache.qpid.protocol.AMQMethodEvent;
+
+public class ConnectionOpenOkMethodHandler implements StateAwareMethodListener
+{
+ private static final ConnectionOpenOkMethodHandler _instance = new ConnectionOpenOkMethodHandler();
+
+ public static ConnectionOpenOkMethodHandler getInstance()
+ {
+ return _instance;
+ }
+
+ private ConnectionOpenOkMethodHandler()
+ {
+ }
+
+ public void methodReceived(AMQStateManager stateManager, AMQProtocolSession protocolSession, AMQMethodEvent evt) throws AMQException
+ {
+ stateManager.changeState(AMQState.CONNECTION_OPEN);
+ }
+
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/client/handler/ConnectionRedirectMethodHandler.java b/Final/java/client/src/main/java/org/apache/qpid/client/handler/ConnectionRedirectMethodHandler.java
new file mode 100644
index 0000000000..213c0eba6e
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/handler/ConnectionRedirectMethodHandler.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.client.handler;
+
+import org.apache.qpid.AMQException;
+import org.apache.qpid.client.protocol.AMQProtocolSession;
+import org.apache.qpid.client.state.AMQStateManager;
+import org.apache.qpid.client.state.StateAwareMethodListener;
+import org.apache.qpid.framing.ConnectionRedirectBody;
+import org.apache.qpid.protocol.AMQMethodEvent;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ConnectionRedirectMethodHandler implements StateAwareMethodListener
+{
+ private static final Logger _logger = LoggerFactory.getLogger(ConnectionRedirectMethodHandler.class);
+
+ private static final int DEFAULT_REDIRECT_PORT = 5672;
+
+ private static ConnectionRedirectMethodHandler _handler = new ConnectionRedirectMethodHandler();
+
+ public static ConnectionRedirectMethodHandler getInstance()
+ {
+ return _handler;
+ }
+
+ private ConnectionRedirectMethodHandler()
+ { }
+
+ public void methodReceived(AMQStateManager stateManager, AMQProtocolSession protocolSession, AMQMethodEvent evt)
+ throws AMQException
+ {
+ _logger.info("ConnectionRedirect frame received");
+ ConnectionRedirectBody method = (ConnectionRedirectBody) evt.getMethod();
+
+ String host = method.host.toString();
+ // the host is in the form hostname:port with the port being optional
+ int portIndex = host.indexOf(':');
+
+ int port;
+ if (portIndex == -1)
+ {
+ port = DEFAULT_REDIRECT_PORT;
+ }
+ else
+ {
+ port = Integer.parseInt(host.substring(portIndex + 1));
+ host = host.substring(0, portIndex);
+
+ }
+
+ protocolSession.failover(host, port);
+ }
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/client/handler/ConnectionSecureMethodHandler.java b/Final/java/client/src/main/java/org/apache/qpid/client/handler/ConnectionSecureMethodHandler.java
new file mode 100644
index 0000000000..ab6acffeaf
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/handler/ConnectionSecureMethodHandler.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.client.handler;
+
+import javax.security.sasl.SaslClient;
+import javax.security.sasl.SaslException;
+
+import org.apache.qpid.AMQException;
+import org.apache.qpid.client.protocol.AMQProtocolSession;
+import org.apache.qpid.client.state.AMQStateManager;
+import org.apache.qpid.client.state.StateAwareMethodListener;
+import org.apache.qpid.framing.AMQFrame;
+import org.apache.qpid.framing.ConnectionSecureBody;
+import org.apache.qpid.framing.ConnectionSecureOkBody;
+import org.apache.qpid.protocol.AMQMethodEvent;
+
+public class ConnectionSecureMethodHandler implements StateAwareMethodListener
+{
+ private static final ConnectionSecureMethodHandler _instance = new ConnectionSecureMethodHandler();
+
+ public static ConnectionSecureMethodHandler getInstance()
+ {
+ return _instance;
+ }
+
+ public void methodReceived(AMQStateManager stateManager, AMQProtocolSession protocolSession, AMQMethodEvent evt) throws AMQException
+ {
+ SaslClient client = protocolSession.getSaslClient();
+ if (client == null)
+ {
+ throw new AMQException("No SASL client set up - cannot proceed with authentication");
+ }
+
+ ConnectionSecureBody body = (ConnectionSecureBody) evt.getMethod();
+
+ try
+ {
+ // Evaluate server challenge
+ byte[] response = client.evaluateChallenge(body.challenge);
+ // AMQP version change: Hardwire the version to 0-8 (major=8, minor=0)
+ // TODO: Connect this to the session version obtained from ProtocolInitiation for this session.
+ // Be aware of possible changes to parameter order as versions change.
+ AMQFrame responseFrame = ConnectionSecureOkBody.createAMQFrame(evt.getChannelId(),
+ body.getMajor(), body.getMinor(),
+ response); // response
+ protocolSession.writeFrame(responseFrame);
+ }
+ catch (SaslException e)
+ {
+ throw new AMQException("Error processing SASL challenge: " + e, e);
+ }
+
+
+ }
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/client/handler/ConnectionStartMethodHandler.java b/Final/java/client/src/main/java/org/apache/qpid/client/handler/ConnectionStartMethodHandler.java
new file mode 100644
index 0000000000..f14e256172
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/handler/ConnectionStartMethodHandler.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.client.handler;
+
+import org.apache.qpid.AMQException;
+import org.apache.qpid.client.protocol.AMQProtocolSession;
+import org.apache.qpid.client.security.AMQCallbackHandler;
+import org.apache.qpid.client.security.CallbackHandlerRegistry;
+import org.apache.qpid.client.state.AMQState;
+import org.apache.qpid.client.state.AMQStateManager;
+import org.apache.qpid.client.state.StateAwareMethodListener;
+import org.apache.qpid.common.ClientProperties;
+import org.apache.qpid.common.QpidProperties;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.framing.ConnectionStartBody;
+import org.apache.qpid.framing.ConnectionStartOkBody;
+import org.apache.qpid.framing.FieldTable;
+import org.apache.qpid.framing.FieldTableFactory;
+import org.apache.qpid.framing.ProtocolVersion;
+import org.apache.qpid.protocol.AMQMethodEvent;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.security.sasl.Sasl;
+import javax.security.sasl.SaslClient;
+import javax.security.sasl.SaslException;
+
+import java.io.UnsupportedEncodingException;
+import java.util.HashSet;
+import java.util.StringTokenizer;
+
+public class ConnectionStartMethodHandler implements StateAwareMethodListener
+{
+ private static final Logger _log = LoggerFactory.getLogger(ConnectionStartMethodHandler.class);
+
+ private static final ConnectionStartMethodHandler _instance = new ConnectionStartMethodHandler();
+
+ public static ConnectionStartMethodHandler getInstance()
+ {
+ return _instance;
+ }
+
+ private ConnectionStartMethodHandler()
+ { }
+
+ public void methodReceived(AMQStateManager stateManager, AMQProtocolSession protocolSession, AMQMethodEvent evt)
+ throws AMQException
+ {
+ _log.debug("public void methodReceived(AMQStateManager stateManager, AMQProtocolSession protocolSession, "
+ + "AMQMethodEvent evt): called");
+
+ ConnectionStartBody body = (ConnectionStartBody) evt.getMethod();
+
+ ProtocolVersion pv = new ProtocolVersion((byte) body.versionMajor, (byte) body.versionMinor);
+
+ // 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.
+ if (Boolean.getBoolean("qpid.accept.broker.version") && !pv.isSupported())
+ {
+
+ pv = ProtocolVersion.getLatestSupportedVersion();
+ }
+
+ if (pv.isSupported())
+ {
+ protocolSession.setProtocolVersion(pv.getMajorVersion(), pv.getMinorVersion());
+
+ try
+ {
+ // Used to hold the SASL mechanism to authenticate with.
+ String mechanism;
+
+ if (body.mechanisms == null)
+ {
+ throw new AMQException("mechanism not specified in ConnectionStart method frame");
+ }
+ else
+ {
+ mechanism = chooseMechanism(body.mechanisms);
+ _log.debug("mechanism = " + mechanism);
+ }
+
+ if (mechanism == null)
+ {
+ throw new AMQException("No supported security mechanism found, passed: " + new String(body.mechanisms));
+ }
+
+ byte[] saslResponse;
+ try
+ {
+ SaslClient sc =
+ Sasl.createSaslClient(new String[] { mechanism }, null, "AMQP", "localhost", null,
+ createCallbackHandler(mechanism, protocolSession));
+ if (sc == null)
+ {
+ throw new AMQException(
+ "Client SASL configuration error: no SaslClient could be created for mechanism " + mechanism
+ + ". Please ensure all factories are registered. See DynamicSaslRegistrar for "
+ + " details of how to register non-standard SASL client providers.");
+ }
+
+ protocolSession.setSaslClient(sc);
+ saslResponse = (sc.hasInitialResponse() ? sc.evaluateChallenge(new byte[0]) : null);
+ }
+ catch (SaslException e)
+ {
+ protocolSession.setSaslClient(null);
+ throw new AMQException("Unable to create SASL client: " + e, e);
+ }
+
+ if (body.locales == null)
+ {
+ throw new AMQException("Locales is not defined in Connection Start method");
+ }
+
+ final String locales = new String(body.locales, "utf8");
+ final StringTokenizer tokenizer = new StringTokenizer(locales, " ");
+ String selectedLocale = null;
+ if (tokenizer.hasMoreTokens())
+ {
+ selectedLocale = tokenizer.nextToken();
+ }
+ else
+ {
+ throw new AMQException("No locales sent from server, passed: " + locales);
+ }
+
+ stateManager.changeState(AMQState.CONNECTION_NOT_TUNED);
+ FieldTable clientProperties = FieldTableFactory.newFieldTable();
+
+ clientProperties.setString(new AMQShortString(ClientProperties.instance.toString()),
+ protocolSession.getClientID());
+ clientProperties.setString(new AMQShortString(ClientProperties.product.toString()),
+ QpidProperties.getProductName());
+ clientProperties.setString(new AMQShortString(ClientProperties.version.toString()),
+ QpidProperties.getReleaseVersion());
+ clientProperties.setString(new AMQShortString(ClientProperties.platform.toString()), getFullSystemInfo());
+
+ // AMQP version change: Hardwire the version to 0-8 (major=8, minor=0)
+ // TODO: Connect this to the session version obtained from ProtocolInitiation for this session.
+ // Be aware of possible changes to parameter order as versions change.
+ protocolSession.writeFrame(ConnectionStartOkBody.createAMQFrame(evt.getChannelId(),
+ protocolSession.getProtocolMajorVersion(), protocolSession.getProtocolMinorVersion(),
+ clientProperties, // clientProperties
+ new AMQShortString(selectedLocale), // locale
+ new AMQShortString(mechanism), // mechanism
+ saslResponse)); // response
+
+ }
+ catch (UnsupportedEncodingException e)
+ {
+ throw new AMQException("Unable to decode data: " + e, e);
+ }
+ }
+ else
+ {
+ _log.error("Broker requested Protocol [" + body.versionMajor + "-" + body.versionMinor
+ + "] which is not supported by this version of the client library");
+
+ protocolSession.closeProtocolSession();
+ }
+ }
+
+ private String getFullSystemInfo()
+ {
+ StringBuffer fullSystemInfo = new StringBuffer();
+ fullSystemInfo.append(System.getProperty("java.runtime.name"));
+ fullSystemInfo.append(", " + System.getProperty("java.runtime.version"));
+ fullSystemInfo.append(", " + System.getProperty("java.vendor"));
+ fullSystemInfo.append(", " + System.getProperty("os.arch"));
+ fullSystemInfo.append(", " + System.getProperty("os.name"));
+ fullSystemInfo.append(", " + System.getProperty("os.version"));
+ fullSystemInfo.append(", " + System.getProperty("sun.os.patch.level"));
+
+ return fullSystemInfo.toString();
+ }
+
+ private String chooseMechanism(byte[] availableMechanisms) throws UnsupportedEncodingException
+ {
+ final String mechanisms = new String(availableMechanisms, "utf8");
+ StringTokenizer tokenizer = new StringTokenizer(mechanisms, " ");
+ HashSet mechanismSet = new HashSet();
+ while (tokenizer.hasMoreTokens())
+ {
+ mechanismSet.add(tokenizer.nextToken());
+ }
+
+ 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;
+ }
+
+ private AMQCallbackHandler createCallbackHandler(String mechanism, AMQProtocolSession protocolSession)
+ throws AMQException
+ {
+ Class mechanismClass = CallbackHandlerRegistry.getInstance().getCallbackHandlerClass(mechanism);
+ try
+ {
+ Object instance = mechanismClass.newInstance();
+ AMQCallbackHandler cbh = (AMQCallbackHandler) instance;
+ cbh.initialise(protocolSession);
+
+ return cbh;
+ }
+ catch (Exception e)
+ {
+ throw new AMQException("Unable to create callback handler: " + e, e);
+ }
+ }
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/client/handler/ConnectionTuneMethodHandler.java b/Final/java/client/src/main/java/org/apache/qpid/client/handler/ConnectionTuneMethodHandler.java
new file mode 100644
index 0000000000..68556991d7
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/handler/ConnectionTuneMethodHandler.java
@@ -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.
+ *
+ */
+package org.apache.qpid.client.handler;
+
+import org.apache.qpid.AMQException;
+import org.apache.qpid.client.ConnectionTuneParameters;
+import org.apache.qpid.client.protocol.AMQProtocolSession;
+import org.apache.qpid.client.state.AMQState;
+import org.apache.qpid.client.state.AMQStateManager;
+import org.apache.qpid.client.state.StateAwareMethodListener;
+import org.apache.qpid.framing.AMQFrame;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.framing.ConnectionOpenBody;
+import org.apache.qpid.framing.ConnectionTuneBody;
+import org.apache.qpid.framing.ConnectionTuneOkBody;
+import org.apache.qpid.protocol.AMQMethodEvent;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ConnectionTuneMethodHandler implements StateAwareMethodListener
+{
+ private static final Logger _logger = LoggerFactory.getLogger(ConnectionTuneMethodHandler.class);
+
+ private static final ConnectionTuneMethodHandler _instance = new ConnectionTuneMethodHandler();
+
+ public static ConnectionTuneMethodHandler getInstance()
+ {
+ return _instance;
+ }
+
+ protected ConnectionTuneMethodHandler()
+ { }
+
+ public void methodReceived(AMQStateManager stateManager, AMQProtocolSession protocolSession, AMQMethodEvent evt)
+ throws AMQException
+ {
+ _logger.debug("ConnectionTune frame received");
+ ConnectionTuneBody frame = (ConnectionTuneBody) evt.getMethod();
+
+ ConnectionTuneParameters params = protocolSession.getConnectionTuneParameters();
+ if (params == null)
+ {
+ params = new ConnectionTuneParameters();
+ }
+
+ params.setFrameMax(frame.frameMax);
+ params.setChannelMax(frame.channelMax);
+ params.setHeartbeat(Integer.getInteger("amqj.heartbeat.delay", frame.heartbeat));
+ protocolSession.setConnectionTuneParameters(params);
+
+ stateManager.changeState(AMQState.CONNECTION_NOT_OPENED);
+ protocolSession.writeFrame(createTuneOkFrame(evt.getChannelId(), params, frame.getMajor(), frame.getMinor()));
+
+ String host = protocolSession.getAMQConnection().getVirtualHost();
+ AMQShortString virtualHost = new AMQShortString("/" + host);
+
+ protocolSession.writeFrame(createConnectionOpenFrame(evt.getChannelId(), virtualHost, null, true, frame.getMajor(),
+ frame.getMinor()));
+ }
+
+ protected AMQFrame createConnectionOpenFrame(int channel, AMQShortString path, AMQShortString capabilities,
+ boolean insist, byte major, byte minor)
+ {
+ // Be aware of possible changes to parameter order as versions change.
+ return ConnectionOpenBody.createAMQFrame(channel, major, minor, // AMQP version (major, minor)
+ capabilities, // capabilities
+ insist, // insist
+ path); // virtualHost
+ }
+
+ protected AMQFrame createTuneOkFrame(int channel, ConnectionTuneParameters params, byte major, byte minor)
+ {
+ // Be aware of possible changes to parameter order as versions change.
+ return ConnectionTuneOkBody.createAMQFrame(channel, major, minor, params.getChannelMax(), // channelMax
+ params.getFrameMax(), // frameMax
+ params.getHeartbeat()); // heartbeat
+ }
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/client/handler/ExchangeBoundOkMethodHandler.java b/Final/java/client/src/main/java/org/apache/qpid/client/handler/ExchangeBoundOkMethodHandler.java
new file mode 100644
index 0000000000..862a9be8d4
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/handler/ExchangeBoundOkMethodHandler.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.client.handler;
+
+import org.apache.qpid.AMQException;
+import org.apache.qpid.client.protocol.AMQProtocolSession;
+import org.apache.qpid.client.state.AMQStateManager;
+import org.apache.qpid.client.state.StateAwareMethodListener;
+import org.apache.qpid.framing.ExchangeBoundOkBody;
+import org.apache.qpid.protocol.AMQMethodEvent;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * @author Apache Software Foundation
+ */
+public class ExchangeBoundOkMethodHandler implements StateAwareMethodListener
+{
+ private static final Logger _logger = LoggerFactory.getLogger(ExchangeBoundOkMethodHandler.class);
+ private static final ExchangeBoundOkMethodHandler _instance = new ExchangeBoundOkMethodHandler();
+
+ public static ExchangeBoundOkMethodHandler getInstance()
+ {
+ return _instance;
+ }
+
+ private ExchangeBoundOkMethodHandler()
+ { }
+
+ public void methodReceived(AMQStateManager stateManager, AMQProtocolSession protocolSession, AMQMethodEvent evt)
+ throws AMQException
+ {
+ if (_logger.isDebugEnabled())
+ {
+ ExchangeBoundOkBody body = (ExchangeBoundOkBody) evt.getMethod();
+ _logger.debug("Received Exchange.Bound-Ok message, response code: " + body.replyCode + " text: "
+ + body.replyText);
+ }
+ }
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/client/handler/QueueDeleteOkMethodHandler.java b/Final/java/client/src/main/java/org/apache/qpid/client/handler/QueueDeleteOkMethodHandler.java
new file mode 100644
index 0000000000..65060d44d2
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/handler/QueueDeleteOkMethodHandler.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.client.handler;
+
+import org.apache.qpid.AMQException;
+import org.apache.qpid.client.protocol.AMQProtocolSession;
+import org.apache.qpid.client.state.AMQStateManager;
+import org.apache.qpid.client.state.StateAwareMethodListener;
+import org.apache.qpid.framing.QueueDeleteOkBody;
+import org.apache.qpid.protocol.AMQMethodEvent;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * @author Apache Software Foundation
+ */
+public class QueueDeleteOkMethodHandler implements StateAwareMethodListener
+{
+ private static final Logger _logger = LoggerFactory.getLogger(QueueDeleteOkMethodHandler.class);
+ private static final QueueDeleteOkMethodHandler _instance = new QueueDeleteOkMethodHandler();
+
+ public static QueueDeleteOkMethodHandler getInstance()
+ {
+ return _instance;
+ }
+
+ private QueueDeleteOkMethodHandler()
+ { }
+
+ public void methodReceived(AMQStateManager stateManager, AMQProtocolSession protocolSession, AMQMethodEvent evt)
+ throws AMQException
+ {
+ if (_logger.isDebugEnabled())
+ {
+ QueueDeleteOkBody body = (QueueDeleteOkBody) evt.getMethod();
+ _logger.debug("Received Queue.Delete-Ok message, message count: " + body.messageCount);
+ }
+ }
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/client/message/AMQMessage.java b/Final/java/client/src/main/java/org/apache/qpid/client/message/AMQMessage.java
new file mode 100644
index 0000000000..8741a1cbb6
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/message/AMQMessage.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.client.message;
+
+import javax.jms.JMSException;
+
+import org.apache.qpid.client.AMQSession;
+import org.apache.qpid.framing.ContentHeaderProperties;
+import org.apache.qpid.framing.BasicContentHeaderProperties;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.framing.FieldTable;
+
+import java.math.BigDecimal;
+
+public class AMQMessage
+{
+ protected ContentHeaderProperties _contentHeaderProperties;
+
+ /** If the acknowledge mode is CLIENT_ACKNOWLEDGE the session is required */
+ protected AMQSession _session;
+
+ protected final long _deliveryTag;
+
+ public AMQMessage(ContentHeaderProperties properties, long deliveryTag)
+ {
+ _contentHeaderProperties = properties;
+ _deliveryTag = deliveryTag;
+ }
+
+ public AMQMessage(ContentHeaderProperties properties)
+ {
+ this(properties, -1);
+ }
+
+ /**
+ * The session is set when CLIENT_ACKNOWLEDGE mode is used so that the CHANNEL ACK can be sent when the user calls
+ * acknowledge()
+ *
+ * @param s the AMQ session that delivered this message
+ */
+ public void setAMQSession(AMQSession s)
+ {
+ _session = s;
+ }
+
+ public AMQSession getAMQSession()
+ {
+ return _session;
+ }
+
+ /**
+ * Get the AMQ message number assigned to this message
+ *
+ * @return the message number
+ */
+ public long getDeliveryTag()
+ {
+ return _deliveryTag;
+ }
+
+ /** Invoked prior to sending the message. Allows the message to be modified if necessary before sending. */
+ public void prepareForSending() throws JMSException
+ {
+ }
+
+ public FieldTable getPropertyHeaders()
+ {
+ return ((BasicContentHeaderProperties) _contentHeaderProperties).getHeaders();
+ }
+
+ public void setDecimalProperty(AMQShortString propertyName, BigDecimal bd) throws JMSException
+ {
+ getPropertyHeaders().setDecimal(propertyName, bd);
+ }
+
+ public void setIntProperty(AMQShortString propertyName, int i) throws JMSException
+ {
+ getPropertyHeaders().setInteger(propertyName, new Integer(i));
+ }
+
+ public void setLongStringProperty(AMQShortString propertyName, String value)
+ {
+ getPropertyHeaders().setString(propertyName, value);
+ }
+
+ public void setTimestampProperty(AMQShortString propertyName, long value)
+ {
+ getPropertyHeaders().setTimestamp(propertyName, value);
+ }
+
+ public void setVoidProperty(AMQShortString propertyName)
+ {
+ getPropertyHeaders().setVoid(propertyName);
+ }
+
+ //** Getters
+
+ public BigDecimal getDecimalProperty(AMQShortString propertyName) throws JMSException
+ {
+ return getPropertyHeaders().getDecimal(propertyName);
+ }
+
+ public int getIntegerProperty(AMQShortString propertyName) throws JMSException
+ {
+ return getPropertyHeaders().getInteger(propertyName);
+ }
+
+ public String getLongStringProperty(AMQShortString propertyName)
+ {
+ return getPropertyHeaders().getString(propertyName);
+ }
+
+ public Long getTimestampProperty(AMQShortString propertyName)
+ {
+ return getPropertyHeaders().getTimestamp(propertyName);
+ }
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/client/message/AbstractBytesMessage.java b/Final/java/client/src/main/java/org/apache/qpid/client/message/AbstractBytesMessage.java
new file mode 100644
index 0000000000..af254fbbaf
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/message/AbstractBytesMessage.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 java.io.IOException;
+import java.nio.charset.Charset;
+
+import javax.jms.JMSException;
+import javax.jms.MessageEOFException;
+
+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.ContentHeaderBody;
+
+/**
+ * @author Apache Software Foundation
+ */
+public abstract class AbstractBytesMessage extends AbstractJMSMessage
+{
+
+ /**
+ * The default initial size of the buffer. The buffer expands automatically.
+ */
+ private static final int DEFAULT_BUFFER_INITIAL_SIZE = 1024;
+
+ AbstractBytesMessage()
+ {
+ this(null);
+ }
+
+ /**
+ * Construct a bytes message with existing data.
+ *
+ * @param data the data that comprises this message. If data is null, you get a 1024 byte buffer that is
+ * set to auto expand
+ */
+ AbstractBytesMessage(ByteBuffer data)
+ {
+ super(data); // this instanties a content header
+ getContentHeaderProperties().setContentType(getMimeTypeAsShortString());
+
+ if (_data == null)
+ {
+ allocateInitialBuffer();
+ }
+ }
+
+ protected void allocateInitialBuffer()
+ {
+ _data = ByteBuffer.allocate(DEFAULT_BUFFER_INITIAL_SIZE);
+ _data.setAutoExpand(true);
+ }
+
+ AbstractBytesMessage(long messageNbr, ContentHeaderBody contentHeader, AMQShortString exchange,
+ AMQShortString routingKey, ByteBuffer data) throws AMQException
+ {
+ // TODO: this casting is ugly. Need to review whole ContentHeaderBody idea
+ super(messageNbr, (BasicContentHeaderProperties) contentHeader.properties, exchange, routingKey, data);
+ getContentHeaderProperties().setContentType(getMimeTypeAsShortString());
+ }
+
+ public void clearBodyImpl() throws JMSException
+ {
+ allocateInitialBuffer();
+ }
+
+ public String toBodyString() throws JMSException
+ {
+ checkReadable();
+ try
+ {
+ return getText();
+ }
+ catch (IOException 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;
+ }
+ }
+
+ /**
+ * Check that there is at least a certain number of bytes available to read
+ *
+ * @param len the number of bytes
+ * @throws javax.jms.MessageEOFException if there are less than len bytes available to read
+ */
+ protected void checkAvailable(int len) throws MessageEOFException
+ {
+ if (_data.remaining() < len)
+ {
+ throw new MessageEOFException("Unable to read " + len + " bytes");
+ }
+ }
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/client/message/AbstractBytesTypedMessage.java b/Final/java/client/src/main/java/org/apache/qpid/client/message/AbstractBytesTypedMessage.java
new file mode 100644
index 0000000000..3b8ce9a98a
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/message/AbstractBytesTypedMessage.java
@@ -0,0 +1,801 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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 java.nio.charset.CharacterCodingException;
+import java.nio.charset.Charset;
+
+import javax.jms.JMSException;
+import javax.jms.MessageEOFException;
+import javax.jms.MessageFormatException;
+import javax.jms.MessageNotReadableException;
+import javax.jms.MessageNotWriteableException;
+
+import org.apache.mina.common.ByteBuffer;
+import org.apache.qpid.AMQException;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.framing.ContentHeaderBody;
+
+/**
+ * @author Apache Software Foundation
+ */
+public abstract class AbstractBytesTypedMessage extends AbstractBytesMessage
+{
+
+ protected static final byte BOOLEAN_TYPE = (byte) 1;
+
+ protected static final byte BYTE_TYPE = (byte) 2;
+
+ protected static final byte BYTEARRAY_TYPE = (byte) 3;
+
+ protected static final byte SHORT_TYPE = (byte) 4;
+
+ protected static final byte CHAR_TYPE = (byte) 5;
+
+ protected static final byte INT_TYPE = (byte) 6;
+
+ protected static final byte LONG_TYPE = (byte) 7;
+
+ protected static final byte FLOAT_TYPE = (byte) 8;
+
+ protected static final byte DOUBLE_TYPE = (byte) 9;
+
+ protected static final byte STRING_TYPE = (byte) 10;
+
+ protected static final byte NULL_STRING_TYPE = (byte) 11;
+
+ /**
+ * This is set when reading a byte array. The readBytes(byte[]) method supports multiple calls to read
+ * a byte array in multiple chunks, hence this is used to track how much is left to be read
+ */
+ private int _byteArrayRemaining = -1;
+
+ AbstractBytesTypedMessage()
+ {
+ this(null);
+ }
+
+ /**
+ * Construct a stream message with existing data.
+ *
+ * @param data the data that comprises this message. If data is null, you get a 1024 byte buffer that is
+ * set to auto expand
+ */
+ AbstractBytesTypedMessage(ByteBuffer data)
+ {
+ super(data); // this instanties a content header
+ }
+
+
+ AbstractBytesTypedMessage(long messageNbr, ContentHeaderBody contentHeader, AMQShortString exchange,
+ AMQShortString routingKey, ByteBuffer data) throws AMQException
+ {
+ super(messageNbr, contentHeader, exchange, routingKey, data);
+ }
+
+
+ protected byte readWireType() throws MessageFormatException, MessageEOFException,
+ MessageNotReadableException
+ {
+ checkReadable();
+ checkAvailable(1);
+ return _data.get();
+ }
+
+ protected void writeTypeDiscriminator(byte type) throws MessageNotWriteableException
+ {
+ checkWritable();
+ _data.put(type);
+ _changedData = true;
+ }
+
+ protected boolean readBoolean() throws JMSException
+ {
+ int position = _data.position();
+ byte wireType = readWireType();
+ boolean result;
+ try
+ {
+ switch (wireType)
+ {
+ case BOOLEAN_TYPE:
+ checkAvailable(1);
+ result = readBooleanImpl();
+ break;
+ case STRING_TYPE:
+ checkAvailable(1);
+ result = Boolean.parseBoolean(readStringImpl());
+ break;
+ default:
+ _data.position(position);
+ throw new MessageFormatException("Unable to convert " + wireType + " to a boolean");
+ }
+ return result;
+ }
+ catch (RuntimeException e)
+ {
+ _data.position(position);
+ throw e;
+ }
+ }
+
+ private boolean readBooleanImpl()
+ {
+ return _data.get() != 0;
+ }
+
+ protected byte readByte() throws JMSException
+ {
+ int position = _data.position();
+ byte wireType = readWireType();
+ byte result;
+ try
+ {
+ switch (wireType)
+ {
+ case BYTE_TYPE:
+ checkAvailable(1);
+ result = readByteImpl();
+ break;
+ case STRING_TYPE:
+ checkAvailable(1);
+ result = Byte.parseByte(readStringImpl());
+ break;
+ default:
+ _data.position(position);
+ throw new MessageFormatException("Unable to convert " + wireType + " to a byte");
+ }
+ }
+ catch (RuntimeException e)
+ {
+ _data.position(position);
+ throw e;
+ }
+ return result;
+ }
+
+ private byte readByteImpl()
+ {
+ return _data.get();
+ }
+
+ protected short readShort() throws JMSException
+ {
+ int position = _data.position();
+ byte wireType = readWireType();
+ short result;
+ try
+ {
+ switch (wireType)
+ {
+ case SHORT_TYPE:
+ checkAvailable(2);
+ result = readShortImpl();
+ break;
+ case STRING_TYPE:
+ checkAvailable(1);
+ result = Short.parseShort(readStringImpl());
+ break;
+ case BYTE_TYPE:
+ checkAvailable(1);
+ result = readByteImpl();
+ break;
+ default:
+ _data.position(position);
+ throw new MessageFormatException("Unable to convert " + wireType + " to a short");
+ }
+ }
+ catch (RuntimeException e)
+ {
+ _data.position(position);
+ throw e;
+ }
+ return result;
+ }
+
+ private short readShortImpl()
+ {
+ return _data.getShort();
+ }
+
+ /**
+ * Note that this method reads a unicode character as two bytes from the stream
+ *
+ * @return the character read from the stream
+ * @throws javax.jms.JMSException
+ */
+ protected char readChar() throws JMSException
+ {
+ int position = _data.position();
+ byte wireType = readWireType();
+ try
+ {
+ if(wireType == NULL_STRING_TYPE){
+ throw new NullPointerException();
+ }
+
+ if (wireType != CHAR_TYPE)
+ {
+ _data.position(position);
+ throw new MessageFormatException("Unable to convert " + wireType + " to a char");
+ }
+ else
+ {
+ checkAvailable(2);
+ return readCharImpl();
+ }
+ }
+ catch (RuntimeException e)
+ {
+ _data.position(position);
+ throw e;
+ }
+ }
+
+ private char readCharImpl()
+ {
+ return _data.getChar();
+ }
+
+ protected int readInt() throws JMSException
+ {
+ int position = _data.position();
+ byte wireType = readWireType();
+ int result;
+ try
+ {
+ switch (wireType)
+ {
+ case INT_TYPE:
+ checkAvailable(4);
+ result = readIntImpl();
+ break;
+ case SHORT_TYPE:
+ checkAvailable(2);
+ result = readShortImpl();
+ break;
+ case STRING_TYPE:
+ checkAvailable(1);
+ result = Integer.parseInt(readStringImpl());
+ break;
+ case BYTE_TYPE:
+ checkAvailable(1);
+ result = readByteImpl();
+ break;
+ default:
+ _data.position(position);
+ throw new MessageFormatException("Unable to convert " + wireType + " to an int");
+ }
+ return result;
+ }
+ catch (RuntimeException e)
+ {
+ _data.position(position);
+ throw e;
+ }
+ }
+
+ protected int readIntImpl()
+ {
+ return _data.getInt();
+ }
+
+ protected long readLong() throws JMSException
+ {
+ int position = _data.position();
+ byte wireType = readWireType();
+ long result;
+ try
+ {
+ switch (wireType)
+ {
+ case LONG_TYPE:
+ checkAvailable(8);
+ result = readLongImpl();
+ break;
+ case INT_TYPE:
+ checkAvailable(4);
+ result = readIntImpl();
+ break;
+ case SHORT_TYPE:
+ checkAvailable(2);
+ result = readShortImpl();
+ break;
+ case STRING_TYPE:
+ checkAvailable(1);
+ result = Long.parseLong(readStringImpl());
+ break;
+ case BYTE_TYPE:
+ checkAvailable(1);
+ result = readByteImpl();
+ break;
+ default:
+ _data.position(position);
+ throw new MessageFormatException("Unable to convert " + wireType + " to a long");
+ }
+ return result;
+ }
+ catch (RuntimeException e)
+ {
+ _data.position(position);
+ throw e;
+ }
+ }
+
+ private long readLongImpl()
+ {
+ return _data.getLong();
+ }
+
+ protected float readFloat() throws JMSException
+ {
+ int position = _data.position();
+ byte wireType = readWireType();
+ float result;
+ try
+ {
+ switch (wireType)
+ {
+ case FLOAT_TYPE:
+ checkAvailable(4);
+ result = readFloatImpl();
+ break;
+ case STRING_TYPE:
+ checkAvailable(1);
+ result = Float.parseFloat(readStringImpl());
+ break;
+ default:
+ _data.position(position);
+ throw new MessageFormatException("Unable to convert " + wireType + " to a float");
+ }
+ return result;
+ }
+ catch (RuntimeException e)
+ {
+ _data.position(position);
+ throw e;
+ }
+ }
+
+ private float readFloatImpl()
+ {
+ return _data.getFloat();
+ }
+
+ protected double readDouble() throws JMSException
+ {
+ int position = _data.position();
+ byte wireType = readWireType();
+ double result;
+ try
+ {
+ switch (wireType)
+ {
+ case DOUBLE_TYPE:
+ checkAvailable(8);
+ result = readDoubleImpl();
+ break;
+ case FLOAT_TYPE:
+ checkAvailable(4);
+ result = readFloatImpl();
+ break;
+ case STRING_TYPE:
+ checkAvailable(1);
+ result = Double.parseDouble(readStringImpl());
+ break;
+ default:
+ _data.position(position);
+ throw new MessageFormatException("Unable to convert " + wireType + " to a double");
+ }
+ return result;
+ }
+ catch (RuntimeException e)
+ {
+ _data.position(position);
+ throw e;
+ }
+ }
+
+ private double readDoubleImpl()
+ {
+ return _data.getDouble();
+ }
+
+ protected String readString() throws JMSException
+ {
+ int position = _data.position();
+ byte wireType = readWireType();
+ String result;
+ try
+ {
+ switch (wireType)
+ {
+ case STRING_TYPE:
+ checkAvailable(1);
+ result = readStringImpl();
+ break;
+ case NULL_STRING_TYPE:
+ result = null;
+ throw new NullPointerException("data is null");
+ case BOOLEAN_TYPE:
+ checkAvailable(1);
+ result = String.valueOf(readBooleanImpl());
+ break;
+ case LONG_TYPE:
+ checkAvailable(8);
+ result = String.valueOf(readLongImpl());
+ break;
+ case INT_TYPE:
+ checkAvailable(4);
+ result = String.valueOf(readIntImpl());
+ break;
+ case SHORT_TYPE:
+ checkAvailable(2);
+ result = String.valueOf(readShortImpl());
+ break;
+ case BYTE_TYPE:
+ checkAvailable(1);
+ result = String.valueOf(readByteImpl());
+ break;
+ case FLOAT_TYPE:
+ checkAvailable(4);
+ result = String.valueOf(readFloatImpl());
+ break;
+ case DOUBLE_TYPE:
+ checkAvailable(8);
+ result = String.valueOf(readDoubleImpl());
+ break;
+ case CHAR_TYPE:
+ checkAvailable(2);
+ result = String.valueOf(readCharImpl());
+ break;
+ default:
+ _data.position(position);
+ throw new MessageFormatException("Unable to convert " + wireType + " to a String");
+ }
+ return result;
+ }
+ catch (RuntimeException e)
+ {
+ _data.position(position);
+ throw e;
+ }
+ }
+
+ protected String readStringImpl() throws JMSException
+ {
+ try
+ {
+ return _data.getString(Charset.forName("UTF-8").newDecoder());
+ }
+ catch (CharacterCodingException e)
+ {
+ JMSException je = new JMSException("Error decoding byte stream as a UTF8 string: " + e);
+ je.setLinkedException(e);
+ throw je;
+ }
+ }
+
+ protected int readBytes(byte[] bytes) throws JMSException
+ {
+ if (bytes == null)
+ {
+ throw new IllegalArgumentException("byte array must not be null");
+ }
+ checkReadable();
+ // first call
+ if (_byteArrayRemaining == -1)
+ {
+ // type discriminator checked separately so you get a MessageFormatException rather than
+ // an EOF even in the case where both would be applicable
+ checkAvailable(1);
+ byte wireType = readWireType();
+ if (wireType != BYTEARRAY_TYPE)
+ {
+ throw new MessageFormatException("Unable to convert " + wireType + " to a byte array");
+ }
+ checkAvailable(4);
+ int size = _data.getInt();
+ // length of -1 indicates null
+ if (size == -1)
+ {
+ return -1;
+ }
+ else
+ {
+ if (size > _data.remaining())
+ {
+ throw new MessageEOFException("Byte array has stated length " + size + " but message only contains " +
+ _data.remaining() + " bytes");
+ }
+ else
+ {
+ _byteArrayRemaining = size;
+ }
+ }
+ }
+ else if (_byteArrayRemaining == 0)
+ {
+ _byteArrayRemaining = -1;
+ return -1;
+ }
+
+ int returnedSize = readBytesImpl(bytes);
+ if (returnedSize < bytes.length)
+ {
+ _byteArrayRemaining = -1;
+ }
+ return returnedSize;
+ }
+
+ private int readBytesImpl(byte[] bytes)
+ {
+ int count = (_byteArrayRemaining >= bytes.length ? bytes.length : _byteArrayRemaining);
+ _byteArrayRemaining -= count;
+
+ if (count == 0)
+ {
+ return 0;
+ }
+ else
+ {
+ _data.get(bytes, 0, count);
+ return count;
+ }
+ }
+
+ protected Object readObject() throws JMSException
+ {
+ int position = _data.position();
+ byte wireType = readWireType();
+ Object result = null;
+ try
+ {
+ switch (wireType)
+ {
+ case BOOLEAN_TYPE:
+ checkAvailable(1);
+ result = readBooleanImpl();
+ break;
+ case BYTE_TYPE:
+ checkAvailable(1);
+ result = readByteImpl();
+ break;
+ case BYTEARRAY_TYPE:
+ checkAvailable(4);
+ int size = _data.getInt();
+ if (size == -1)
+ {
+ result = null;
+ }
+ else
+ {
+ _byteArrayRemaining = size;
+ byte[] bytesResult = new byte[size];
+ readBytesImpl(bytesResult);
+ result = bytesResult;
+ }
+ break;
+ case SHORT_TYPE:
+ checkAvailable(2);
+ result = readShortImpl();
+ break;
+ case CHAR_TYPE:
+ checkAvailable(2);
+ result = readCharImpl();
+ break;
+ case INT_TYPE:
+ checkAvailable(4);
+ result = readIntImpl();
+ break;
+ case LONG_TYPE:
+ checkAvailable(8);
+ result = readLongImpl();
+ break;
+ case FLOAT_TYPE:
+ checkAvailable(4);
+ result = readFloatImpl();
+ break;
+ case DOUBLE_TYPE:
+ checkAvailable(8);
+ result = readDoubleImpl();
+ break;
+ case NULL_STRING_TYPE:
+ result = null;
+ break;
+ case STRING_TYPE:
+ checkAvailable(1);
+ result = readStringImpl();
+ break;
+ }
+ return result;
+ }
+ catch (RuntimeException e)
+ {
+ _data.position(position);
+ throw e;
+ }
+ }
+
+ protected void writeBoolean(boolean b) throws JMSException
+ {
+ writeTypeDiscriminator(BOOLEAN_TYPE);
+ _data.put(b ? (byte) 1 : (byte) 0);
+ }
+
+ protected void writeByte(byte b) throws JMSException
+ {
+ writeTypeDiscriminator(BYTE_TYPE);
+ _data.put(b);
+ }
+
+ protected void writeShort(short i) throws JMSException
+ {
+ writeTypeDiscriminator(SHORT_TYPE);
+ _data.putShort(i);
+ }
+
+ protected void writeChar(char c) throws JMSException
+ {
+ writeTypeDiscriminator(CHAR_TYPE);
+ _data.putChar(c);
+ }
+
+ protected void writeInt(int i) throws JMSException
+ {
+ writeTypeDiscriminator(INT_TYPE);
+ writeIntImpl(i);
+ }
+
+ protected void writeIntImpl(int i)
+ {
+ _data.putInt(i);
+ }
+
+ protected void writeLong(long l) throws JMSException
+ {
+ writeTypeDiscriminator(LONG_TYPE);
+ _data.putLong(l);
+ }
+
+ protected void writeFloat(float v) throws JMSException
+ {
+ writeTypeDiscriminator(FLOAT_TYPE);
+ _data.putFloat(v);
+ }
+
+ protected void writeDouble(double v) throws JMSException
+ {
+ writeTypeDiscriminator(DOUBLE_TYPE);
+ _data.putDouble(v);
+ }
+
+ protected void writeString(String string) throws JMSException
+ {
+ if (string == null)
+ {
+ writeTypeDiscriminator(NULL_STRING_TYPE);
+ }
+ else
+ {
+ writeTypeDiscriminator(STRING_TYPE);
+ try
+ {
+ writeStringImpl(string);
+ }
+ catch (CharacterCodingException e)
+ {
+ JMSException ex = new JMSException("Unable to encode string: " + e);
+ ex.setLinkedException(e);
+ throw ex;
+ }
+ }
+ }
+
+ protected void writeStringImpl(String string)
+ throws CharacterCodingException
+ {
+ _data.putString(string, Charset.forName("UTF-8").newEncoder());
+ // we must write the null terminator ourselves
+ _data.put((byte) 0);
+ }
+
+ protected void writeBytes(byte[] bytes) throws JMSException
+ {
+ writeBytes(bytes, 0, bytes == null ? 0 : bytes.length);
+ }
+
+ protected void writeBytes(byte[] bytes, int offset, int length) throws JMSException
+ {
+ writeTypeDiscriminator(BYTEARRAY_TYPE);
+ if (bytes == null)
+ {
+ _data.putInt(-1);
+ }
+ else
+ {
+ _data.putInt(length);
+ _data.put(bytes, offset, length);
+ }
+ }
+
+ protected void writeObject(Object object) throws JMSException
+ {
+ checkWritable();
+ Class clazz;
+
+ if (object == null)
+ {
+ // string handles the output of null values
+ clazz = String.class;
+ }
+ else
+ {
+ clazz = object.getClass();
+ }
+
+ if (clazz == Byte.class)
+ {
+ writeByte((Byte) object);
+ }
+ else if (clazz == Boolean.class)
+ {
+ writeBoolean((Boolean) object);
+ }
+ else if (clazz == byte[].class)
+ {
+ writeBytes((byte[]) object);
+ }
+ else if (clazz == Short.class)
+ {
+ writeShort((Short) object);
+ }
+ else if (clazz == Character.class)
+ {
+ writeChar((Character) object);
+ }
+ else if (clazz == Integer.class)
+ {
+ writeInt((Integer) object);
+ }
+ else if (clazz == Long.class)
+ {
+ writeLong((Long) object);
+ }
+ else if (clazz == Float.class)
+ {
+ writeFloat((Float) object);
+ }
+ else if (clazz == Double.class)
+ {
+ writeDouble((Double) object);
+ }
+ else if (clazz == String.class)
+ {
+ writeString((String) object);
+ }
+ else
+ {
+ throw new MessageFormatException("Only primitives plus byte arrays and String are valid types");
+ }
+ }
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/client/message/AbstractJMSMessage.java b/Final/java/client/src/main/java/org/apache/qpid/client/message/AbstractJMSMessage.java
new file mode 100644
index 0000000000..2dfeb19268
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/message/AbstractJMSMessage.java
@@ -0,0 +1,685 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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.commons.collections.map.ReferenceMap;
+
+import org.apache.mina.common.ByteBuffer;
+
+import org.apache.qpid.AMQException;
+import org.apache.qpid.client.*;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.framing.BasicContentHeaderProperties;
+import org.apache.qpid.framing.FieldTable;
+import org.apache.qpid.url.AMQBindingURL;
+import org.apache.qpid.url.BindingURL;
+import org.apache.qpid.url.URLSyntaxException;
+
+import javax.jms.Destination;
+import javax.jms.JMSException;
+import javax.jms.MessageNotReadableException;
+import javax.jms.MessageNotWriteableException;
+
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.Map;
+import java.util.UUID;
+
+public abstract class AbstractJMSMessage extends AMQMessage implements org.apache.qpid.jms.Message
+{
+ private static final Map _destinationCache = Collections.synchronizedMap(new ReferenceMap());
+
+ protected boolean _redelivered;
+
+ protected ByteBuffer _data;
+ private boolean _readableProperties = false;
+ protected boolean _readableMessage = false;
+ protected boolean _changedData;
+ private Destination _destination;
+ private JMSHeaderAdapter _headerAdapter;
+ private BasicMessageConsumer _consumer;
+ private boolean _strictAMQP;
+
+ protected AbstractJMSMessage(ByteBuffer data)
+ {
+ super(new BasicContentHeaderProperties());
+ _data = data;
+ if (_data != null)
+ {
+ _data.acquire();
+ }
+
+ _readableProperties = false;
+ _readableMessage = (data != null);
+ _changedData = (data == null);
+ _headerAdapter = new JMSHeaderAdapter(((BasicContentHeaderProperties) _contentHeaderProperties).getHeaders());
+
+ _strictAMQP =
+ Boolean.parseBoolean(System.getProperties().getProperty(AMQSession.STRICT_AMQP, AMQSession.STRICT_AMQP_DEFAULT));
+ }
+
+ protected AbstractJMSMessage(long deliveryTag, BasicContentHeaderProperties contentHeader, AMQShortString exchange,
+ AMQShortString routingKey, ByteBuffer data) throws AMQException
+ {
+ this(contentHeader, deliveryTag);
+
+ Integer type = contentHeader.getHeaders().getInteger(CustomJMSXProperty.JMS_QPID_DESTTYPE.getShortStringName());
+
+ AMQDestination dest;
+
+ if (AMQDestination.QUEUE_TYPE.equals(type))
+ {
+ dest = new AMQQueue(exchange, routingKey, routingKey);
+ }
+ else if (AMQDestination.TOPIC_TYPE.equals(type))
+ {
+ dest = new AMQTopic(exchange, routingKey, null);
+ }
+ else
+ {
+ dest = new AMQUndefinedDestination(exchange, routingKey, null);
+ }
+ // Destination dest = AMQDestination.createDestination(url);
+ setJMSDestination(dest);
+
+ _data = data;
+ if (_data != null)
+ {
+ _data.acquire();
+ }
+
+ _readableMessage = data != null;
+
+ }
+
+ protected AbstractJMSMessage(BasicContentHeaderProperties contentHeader, long deliveryTag)
+ {
+ super(contentHeader, deliveryTag);
+ _readableProperties = (_contentHeaderProperties != null);
+ _headerAdapter = new JMSHeaderAdapter(((BasicContentHeaderProperties) _contentHeaderProperties).getHeaders());
+ }
+
+ public String getJMSMessageID() throws JMSException
+ {
+ if (getContentHeaderProperties().getMessageIdAsString() == null)
+ {
+ getContentHeaderProperties().setMessageId("ID:" + UUID.randomUUID());
+ }
+
+ return getContentHeaderProperties().getMessageIdAsString();
+ }
+
+ public void setJMSMessageID(String messageId) throws JMSException
+ {
+ getContentHeaderProperties().setMessageId(messageId);
+ }
+
+ public long getJMSTimestamp() throws JMSException
+ {
+ return getContentHeaderProperties().getTimestamp();
+ }
+
+ public void setJMSTimestamp(long timestamp) throws JMSException
+ {
+ getContentHeaderProperties().setTimestamp(timestamp);
+ }
+
+ public byte[] getJMSCorrelationIDAsBytes() throws JMSException
+ {
+ return getContentHeaderProperties().getCorrelationIdAsString().getBytes();
+ }
+
+ public void setJMSCorrelationIDAsBytes(byte[] bytes) throws JMSException
+ {
+ getContentHeaderProperties().setCorrelationId(new String(bytes));
+ }
+
+ public void setJMSCorrelationID(String correlationId) throws JMSException
+ {
+ getContentHeaderProperties().setCorrelationId(correlationId);
+ }
+
+ public String getJMSCorrelationID() throws JMSException
+ {
+ return getContentHeaderProperties().getCorrelationIdAsString();
+ }
+
+ public Destination getJMSReplyTo() throws JMSException
+ {
+ String replyToEncoding = getContentHeaderProperties().getReplyToAsString();
+ if (replyToEncoding == null)
+ {
+ return null;
+ }
+ else
+ {
+ Destination dest = (Destination) _destinationCache.get(replyToEncoding);
+ if (dest == null)
+ {
+ try
+ {
+ BindingURL binding = new AMQBindingURL(replyToEncoding);
+ dest = AMQDestination.createDestination(binding);
+ }
+ catch (URLSyntaxException e)
+ {
+ throw new JMSAMQException("Illegal value in JMS_ReplyTo property: " + replyToEncoding, e);
+ }
+
+ _destinationCache.put(replyToEncoding, dest);
+ }
+
+ return dest;
+ }
+ }
+
+ public void setJMSReplyTo(Destination destination) throws JMSException
+ {
+ if (destination == null)
+ {
+ throw new IllegalArgumentException("Null destination not allowed");
+ }
+
+ if (!(destination instanceof AMQDestination))
+ {
+ throw new IllegalArgumentException(
+ "ReplyTo destination may only be an AMQDestination - passed argument was type " + destination.getClass());
+ }
+
+ final AMQDestination amqd = (AMQDestination) destination;
+
+ final AMQShortString encodedDestination = amqd.getEncodedName();
+ _destinationCache.put(encodedDestination, destination);
+ getContentHeaderProperties().setReplyTo(encodedDestination);
+ }
+
+ public Destination getJMSDestination() throws JMSException
+ {
+ return _destination;
+ }
+
+ public void setJMSDestination(Destination destination)
+ {
+ _destination = destination;
+ }
+
+ public int getJMSDeliveryMode() throws JMSException
+ {
+ return getContentHeaderProperties().getDeliveryMode();
+ }
+
+ public void setJMSDeliveryMode(int i) throws JMSException
+ {
+ getContentHeaderProperties().setDeliveryMode((byte) i);
+ }
+
+ public BasicContentHeaderProperties getContentHeaderProperties()
+ {
+ return (BasicContentHeaderProperties) _contentHeaderProperties;
+ }
+
+ public boolean getJMSRedelivered() throws JMSException
+ {
+ return _redelivered;
+ }
+
+ public void setJMSRedelivered(boolean b) throws JMSException
+ {
+ _redelivered = b;
+ }
+
+ public String getJMSType() throws JMSException
+ {
+ return getContentHeaderProperties().getTypeAsString();
+ }
+
+ public void setJMSType(String string) throws JMSException
+ {
+ getContentHeaderProperties().setType(string);
+ }
+
+ public long getJMSExpiration() throws JMSException
+ {
+ return getContentHeaderProperties().getExpiration();
+ }
+
+ public void setJMSExpiration(long l) throws JMSException
+ {
+ getContentHeaderProperties().setExpiration(l);
+ }
+
+ public int getJMSPriority() throws JMSException
+ {
+ return getContentHeaderProperties().getPriority();
+ }
+
+ public void setJMSPriority(int i) throws JMSException
+ {
+ getContentHeaderProperties().setPriority((byte) i);
+ }
+
+ public void clearProperties() throws JMSException
+ {
+ getJmsHeaders().clear();
+
+ _readableProperties = false;
+ }
+
+ public void clearBody() throws JMSException
+ {
+ clearBodyImpl();
+ _readableMessage = false;
+ }
+
+ public boolean propertyExists(AMQShortString propertyName) throws JMSException
+ {
+ return getJmsHeaders().propertyExists(propertyName);
+ }
+
+ public boolean propertyExists(String propertyName) throws JMSException
+ {
+ return getJmsHeaders().propertyExists(propertyName);
+ }
+
+ public boolean getBooleanProperty(AMQShortString propertyName) throws JMSException
+ {
+ if (_strictAMQP)
+ {
+ throw new UnsupportedOperationException("JMS Proprerties not supported in AMQP");
+ }
+
+ return getJmsHeaders().getBoolean(propertyName);
+ }
+
+ public boolean getBooleanProperty(String propertyName) throws JMSException
+ {
+ if (_strictAMQP)
+ {
+ throw new UnsupportedOperationException("JMS Proprerties not supported in AMQP");
+ }
+
+ return getJmsHeaders().getBoolean(propertyName);
+ }
+
+ public byte getByteProperty(String propertyName) throws JMSException
+ {
+ if (_strictAMQP)
+ {
+ throw new UnsupportedOperationException("JMS Proprerties not supported in AMQP");
+ }
+
+ return getJmsHeaders().getByte(propertyName);
+ }
+
+ public byte[] getBytesProperty(AMQShortString propertyName) throws JMSException
+ {
+ if (_strictAMQP)
+ {
+ throw new UnsupportedOperationException("JMS Proprerties not supported in AMQP");
+ }
+
+ return getJmsHeaders().getBytes(propertyName);
+ }
+
+ public short getShortProperty(String propertyName) throws JMSException
+ {
+ if (_strictAMQP)
+ {
+ throw new UnsupportedOperationException("JMS Proprerties not supported in AMQP");
+ }
+
+ return getJmsHeaders().getShort(propertyName);
+ }
+
+ public int getIntProperty(String propertyName) throws JMSException
+ {
+ if (_strictAMQP)
+ {
+ throw new UnsupportedOperationException("JMS Proprerties not supported in AMQP");
+ }
+
+ return getJmsHeaders().getInteger(propertyName);
+ }
+
+ public long getLongProperty(String propertyName) throws JMSException
+ {
+ if (_strictAMQP)
+ {
+ throw new UnsupportedOperationException("JMS Proprerties not supported in AMQP");
+ }
+
+ return getJmsHeaders().getLong(propertyName);
+ }
+
+ public float getFloatProperty(String propertyName) throws JMSException
+ {
+ if (_strictAMQP)
+ {
+ throw new UnsupportedOperationException("JMS Proprerties not supported in AMQP");
+ }
+
+ return getJmsHeaders().getFloat(propertyName);
+ }
+
+ public double getDoubleProperty(String propertyName) throws JMSException
+ {
+ if (_strictAMQP)
+ {
+ throw new UnsupportedOperationException("JMS Proprerties not supported in AMQP");
+ }
+
+ return getJmsHeaders().getDouble(propertyName);
+ }
+
+ public String getStringProperty(String propertyName) throws JMSException
+ {
+ if (_strictAMQP)
+ {
+ throw new UnsupportedOperationException("JMS Proprerties not supported in AMQP");
+ }
+
+ return getJmsHeaders().getString(propertyName);
+ }
+
+ public Object getObjectProperty(String propertyName) throws JMSException
+ {
+ return getJmsHeaders().getObject(propertyName);
+ }
+
+ public Enumeration getPropertyNames() throws JMSException
+ {
+ return getJmsHeaders().getPropertyNames();
+ }
+
+ public void setBooleanProperty(AMQShortString propertyName, boolean b) throws JMSException
+ {
+ if (_strictAMQP)
+ {
+ throw new UnsupportedOperationException("JMS Proprerties not supported in AMQP");
+ }
+
+ checkWritableProperties();
+ getJmsHeaders().setBoolean(propertyName, b);
+ }
+
+ public void setBooleanProperty(String propertyName, boolean b) throws JMSException
+ {
+ if (_strictAMQP)
+ {
+ throw new UnsupportedOperationException("JMS Proprerties not supported in AMQP");
+ }
+
+ checkWritableProperties();
+ getJmsHeaders().setBoolean(propertyName, b);
+ }
+
+ public void setByteProperty(String propertyName, byte b) throws JMSException
+ {
+ if (_strictAMQP)
+ {
+ throw new UnsupportedOperationException("JMS Proprerties not supported in AMQP");
+ }
+
+ checkWritableProperties();
+ getJmsHeaders().setByte(propertyName, new Byte(b));
+ }
+
+ public void setBytesProperty(AMQShortString propertyName, byte[] bytes) throws JMSException
+ {
+ if (_strictAMQP)
+ {
+ throw new UnsupportedOperationException("JMS Proprerties not supported in AMQP");
+ }
+
+ checkWritableProperties();
+ getJmsHeaders().setBytes(propertyName, bytes);
+ }
+
+ public void setShortProperty(String propertyName, short i) throws JMSException
+ {
+ if (_strictAMQP)
+ {
+ throw new UnsupportedOperationException("JMS Proprerties not supported in AMQP");
+ }
+
+ checkWritableProperties();
+ getJmsHeaders().setShort(propertyName, new Short(i));
+ }
+
+ public void setIntProperty(String propertyName, int i) throws JMSException
+ {
+ checkWritableProperties();
+ JMSHeaderAdapter.checkPropertyName(propertyName);
+ super.setIntProperty(new AMQShortString(propertyName), new Integer(i));
+ }
+
+ public void setLongProperty(String propertyName, long l) throws JMSException
+ {
+ if (_strictAMQP)
+ {
+ throw new UnsupportedOperationException("JMS Proprerties not supported in AMQP");
+ }
+
+ checkWritableProperties();
+ getJmsHeaders().setLong(propertyName, new Long(l));
+ }
+
+ public void setFloatProperty(String propertyName, float f) throws JMSException
+ {
+ if (_strictAMQP)
+ {
+ throw new UnsupportedOperationException("JMS Proprerties not supported in AMQP");
+ }
+
+ checkWritableProperties();
+ getJmsHeaders().setFloat(propertyName, new Float(f));
+ }
+
+ public void setDoubleProperty(String propertyName, double v) throws JMSException
+ {
+ if (_strictAMQP)
+ {
+ throw new UnsupportedOperationException("JMS Proprerties not supported in AMQP");
+ }
+
+ checkWritableProperties();
+ getJmsHeaders().setDouble(propertyName, new Double(v));
+ }
+
+ public void setStringProperty(String propertyName, String value) throws JMSException
+ {
+ checkWritableProperties();
+ JMSHeaderAdapter.checkPropertyName(propertyName);
+ super.setLongStringProperty(new AMQShortString(propertyName), value);
+ }
+
+ public void setObjectProperty(String propertyName, Object object) throws JMSException
+ {
+ checkWritableProperties();
+ getJmsHeaders().setObject(propertyName, object);
+ }
+
+ protected void removeProperty(AMQShortString propertyName) throws JMSException
+ {
+ getJmsHeaders().remove(propertyName);
+ }
+
+ protected void removeProperty(String propertyName) throws JMSException
+ {
+ getJmsHeaders().remove(propertyName);
+ }
+
+ public void acknowledgeThis() throws JMSException
+ {
+ // the JMS 1.1 spec says in section 3.6 that calls to acknowledge are ignored when client acknowledge
+ // is not specified. In our case, we only set the session field where client acknowledge mode is specified.
+ if (_session != null)
+ {
+ if (_session.getAMQConnection().isClosed())
+ {
+ throw new javax.jms.IllegalStateException("Connection is already closed");
+ }
+
+ // we set multiple to true here since acknowledgement implies acknowledge of all previous messages
+ // received on the session
+ _session.acknowledgeMessage(_deliveryTag, true);
+ }
+ }
+
+ public void acknowledge() throws JMSException
+ {
+ if (_session != null)
+ {
+ _session.acknowledge();
+ }
+ }
+
+ /**
+ * This forces concrete classes to implement clearBody()
+ *
+ * @throws JMSException
+ */
+ public abstract void clearBodyImpl() throws JMSException;
+
+ /**
+ * Get a String representation of the body of the message. Used in the toString() method which outputs this before
+ * message properties.
+ */
+ public abstract String toBodyString() throws JMSException;
+
+ public String getMimeType()
+ {
+ return getMimeTypeAsShortString().toString();
+ }
+
+ public abstract AMQShortString getMimeTypeAsShortString();
+
+ public String toString()
+ {
+ 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 Redelivered: ").append(_redelivered);
+ buf.append("\nJMS Destination: ").append(getJMSDestination());
+ buf.append("\nJMS Type: ").append(getJMSType());
+ buf.append("\nJMS MessageID: ").append(getJMSMessageID());
+ buf.append("\nAMQ message number: ").append(_deliveryTag);
+
+ buf.append("\nProperties:");
+ if (getJmsHeaders().isEmpty())
+ {
+ buf.append("<NONE>");
+ }
+ else
+ {
+ buf.append('\n').append(getJmsHeaders().getHeaders());
+ }
+
+ return buf.toString();
+ }
+ catch (JMSException e)
+ {
+ return e.toString();
+ }
+ }
+
+ public void setUnderlyingMessagePropertiesMap(FieldTable messageProperties)
+ {
+ getContentHeaderProperties().setHeaders(messageProperties);
+ }
+
+ public JMSHeaderAdapter getJmsHeaders()
+ {
+ return _headerAdapter;
+ }
+
+ public ByteBuffer getData()
+ {
+ // make sure we rewind the data just in case any method has moved the
+ // position beyond the start
+ if (_data != null)
+ {
+ reset();
+ }
+
+ return _data;
+ }
+
+ protected void checkReadable() throws MessageNotReadableException
+ {
+ if (!_readableMessage)
+ {
+ throw new MessageNotReadableException("You need to call reset() to make the message readable");
+ }
+ }
+
+ protected void checkWritable() throws MessageNotWriteableException
+ {
+ if (_readableMessage)
+ {
+ throw new MessageNotWriteableException("You need to call clearBody() to make the message writable");
+ }
+ }
+
+ protected void checkWritableProperties() throws MessageNotWriteableException
+ {
+ if (_readableProperties)
+ {
+ throw new MessageNotWriteableException("You need to call clearProperties() to make the message writable");
+ }
+ }
+
+ public boolean isReadable()
+ {
+ return _readableMessage;
+ }
+
+ public boolean isWritable()
+ {
+ return !_readableMessage;
+ }
+
+ public void reset()
+ {
+ if (!_changedData)
+ {
+ _data.rewind();
+ }
+ else
+ {
+ _data.flip();
+ _changedData = false;
+ }
+ }
+
+ public void setConsumer(BasicMessageConsumer basicMessageConsumer)
+ {
+ _consumer = basicMessageConsumer;
+ }
+
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/client/message/AbstractJMSMessageFactory.java b/Final/java/client/src/main/java/org/apache/qpid/client/message/AbstractJMSMessageFactory.java
new file mode 100644
index 0000000000..87df7e1337
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/message/AbstractJMSMessageFactory.java
@@ -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.
+ *
+ */
+package org.apache.qpid.client.message;
+
+import org.apache.mina.common.ByteBuffer;
+
+import org.apache.qpid.AMQException;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.framing.ContentBody;
+import org.apache.qpid.framing.ContentHeaderBody;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.jms.JMSException;
+
+import java.util.Iterator;
+import java.util.List;
+
+public abstract class AbstractJMSMessageFactory implements MessageFactory
+{
+ private static final Logger _logger = LoggerFactory.getLogger(AbstractJMSMessageFactory.class);
+
+ protected abstract AbstractJMSMessage createMessage(long messageNbr, ByteBuffer data, AMQShortString exchange,
+ AMQShortString routingKey, ContentHeaderBody contentHeader) throws AMQException;
+
+ protected AbstractJMSMessage createMessageWithBody(long messageNbr, ContentHeaderBody contentHeader,
+ AMQShortString exchange, AMQShortString routingKey, List bodies) throws AMQException
+ {
+ ByteBuffer data;
+ final boolean debug = _logger.isDebugEnabled();
+
+ // we optimise the non-fragmented case to avoid copying
+ if ((bodies != null) && (bodies.size() == 1))
+ {
+ if (debug)
+ {
+ _logger.debug("Non-fragmented message body (bodySize=" + contentHeader.bodySize + ")");
+ }
+
+ data = ((ContentBody) bodies.get(0)).payload;
+ }
+ else if (bodies != null)
+ {
+ if (debug)
+ {
+ _logger.debug("Fragmented message body (" + bodies.size() + " frames, bodySize=" + contentHeader.bodySize
+ + ")");
+ }
+
+ data = ByteBuffer.allocate((int) contentHeader.bodySize); // XXX: Is cast a problem?
+ final Iterator it = bodies.iterator();
+ while (it.hasNext())
+ {
+ ContentBody cb = (ContentBody) it.next();
+ data.put(cb.payload);
+ cb.payload.release();
+ }
+
+ data.flip();
+ }
+ else // bodies == null
+ {
+ data = ByteBuffer.allocate(0);
+ }
+
+ if (debug)
+ {
+ _logger.debug("Creating message from buffer with position=" + data.position() + " and remaining="
+ + data.remaining());
+ }
+
+ return createMessage(messageNbr, data, exchange, routingKey, contentHeader);
+ }
+
+ public AbstractJMSMessage createMessage(long messageNbr, boolean redelivered, ContentHeaderBody contentHeader,
+ AMQShortString exchange, AMQShortString routingKey, List bodies) throws JMSException, AMQException
+ {
+ final AbstractJMSMessage msg = createMessageWithBody(messageNbr, contentHeader, exchange, routingKey, bodies);
+ msg.setJMSRedelivered(redelivered);
+
+ return msg;
+ }
+
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/client/message/JMSBytesMessage.java b/Final/java/client/src/main/java/org/apache/qpid/client/message/JMSBytesMessage.java
new file mode 100644
index 0000000000..19382b58c3
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/message/JMSBytesMessage.java
@@ -0,0 +1,388 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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 java.nio.CharBuffer;
+import java.nio.charset.CharacterCodingException;
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetDecoder;
+import java.nio.charset.CharsetEncoder;
+
+import javax.jms.BytesMessage;
+import javax.jms.JMSException;
+import javax.jms.MessageFormatException;
+
+import org.apache.mina.common.ByteBuffer;
+import org.apache.qpid.AMQException;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.framing.ContentHeaderBody;
+
+public class JMSBytesMessage extends AbstractBytesMessage implements BytesMessage
+{
+ public static final String MIME_TYPE = "application/octet-stream";
+ private static final AMQShortString MIME_TYPE_SHORT_STRING = new AMQShortString(MIME_TYPE);
+
+
+ public JMSBytesMessage()
+ {
+ this(null);
+ }
+
+ /**
+ * Construct a bytes message with existing data.
+ *
+ * @param data the data that comprises this message. If data is null, you get a 1024 byte buffer that is
+ * set to auto expand
+ */
+ JMSBytesMessage(ByteBuffer data)
+ {
+ super(data); // this instanties a content header
+ }
+
+ JMSBytesMessage(long messageNbr, ContentHeaderBody contentHeader, AMQShortString exchange,
+ AMQShortString routingKey, ByteBuffer data) throws AMQException
+ {
+ super(messageNbr, contentHeader, exchange, routingKey, data);
+ }
+
+ public void reset()
+ {
+ super.reset();
+ _readableMessage = true;
+ }
+
+ public AMQShortString getMimeTypeAsShortString()
+ {
+ return MIME_TYPE_SHORT_STRING;
+ }
+
+ public long getBodyLength() throws JMSException
+ {
+ checkReadable();
+ return _data.limit();
+ }
+
+ public boolean readBoolean() throws JMSException
+ {
+ checkReadable();
+ checkAvailable(1);
+ return _data.get() != 0;
+ }
+
+ public byte readByte() throws JMSException
+ {
+ checkReadable();
+ checkAvailable(1);
+ return _data.get();
+ }
+
+ public int readUnsignedByte() throws JMSException
+ {
+ checkReadable();
+ checkAvailable(1);
+ return _data.getUnsigned();
+ }
+
+ public short readShort() throws JMSException
+ {
+ checkReadable();
+ checkAvailable(2);
+ return _data.getShort();
+ }
+
+ public int readUnsignedShort() throws JMSException
+ {
+ checkReadable();
+ checkAvailable(2);
+ return _data.getUnsignedShort();
+ }
+
+ /**
+ * Note that this method reads a unicode character as two bytes from the stream
+ *
+ * @return the character read from the stream
+ * @throws JMSException
+ */
+ public char readChar() throws JMSException
+ {
+ checkReadable();
+ checkAvailable(2);
+ return _data.getChar();
+ }
+
+ public int readInt() throws JMSException
+ {
+ checkReadable();
+ checkAvailable(4);
+ return _data.getInt();
+ }
+
+ public long readLong() throws JMSException
+ {
+ checkReadable();
+ checkAvailable(8);
+ return _data.getLong();
+ }
+
+ public float readFloat() throws JMSException
+ {
+ checkReadable();
+ checkAvailable(4);
+ return _data.getFloat();
+ }
+
+ public double readDouble() throws JMSException
+ {
+ checkReadable();
+ checkAvailable(8);
+ return _data.getDouble();
+ }
+
+ public String readUTF() throws JMSException
+ {
+ checkReadable();
+ // we check only for one byte since theoretically the string could be only a
+ // single byte when using UTF-8 encoding
+
+ try
+ {
+ short length = readShort();
+ if(length == 0)
+ {
+ return "";
+ }
+ else
+ {
+ CharsetDecoder decoder = Charset.forName("UTF-8").newDecoder();
+ ByteBuffer encodedString = _data.slice();
+ encodedString.limit(length);
+ _data.position(_data.position()+length);
+ CharBuffer string = decoder.decode(encodedString.buf());
+
+ return string.toString();
+ }
+
+
+
+ }
+ catch (CharacterCodingException e)
+ {
+ JMSException je = new JMSException("Error decoding byte stream as a UTF8 string: " + e);
+ je.setLinkedException(e);
+ throw je;
+ }
+ }
+
+ public int readBytes(byte[] bytes) throws JMSException
+ {
+ if (bytes == null)
+ {
+ throw new IllegalArgumentException("byte array must not be null");
+ }
+ checkReadable();
+ int count = (_data.remaining() >= bytes.length ? bytes.length : _data.remaining());
+ if (count == 0)
+ {
+ return -1;
+ }
+ else
+ {
+ _data.get(bytes, 0, count);
+ return count;
+ }
+ }
+
+ public int readBytes(byte[] bytes, int maxLength) throws JMSException
+ {
+ if (bytes == null)
+ {
+ throw new IllegalArgumentException("byte array must not be null");
+ }
+ if (maxLength > bytes.length)
+ {
+ throw new IllegalArgumentException("maxLength must be <= bytes.length");
+ }
+ checkReadable();
+ int count = (_data.remaining() >= maxLength ? maxLength : _data.remaining());
+ if (count == 0)
+ {
+ return -1;
+ }
+ else
+ {
+ _data.get(bytes, 0, count);
+ return count;
+ }
+ }
+
+ public void writeBoolean(boolean b) throws JMSException
+ {
+ checkWritable();
+ _changedData = true;
+ _data.put(b ? (byte) 1 : (byte) 0);
+ }
+
+ public void writeByte(byte b) throws JMSException
+ {
+ checkWritable();
+ _changedData = true;
+ _data.put(b);
+ }
+
+ public void writeShort(short i) throws JMSException
+ {
+ checkWritable();
+ _changedData = true;
+ _data.putShort(i);
+ }
+
+ public void writeChar(char c) throws JMSException
+ {
+ checkWritable();
+ _changedData = true;
+ _data.putChar(c);
+ }
+
+ public void writeInt(int i) throws JMSException
+ {
+ checkWritable();
+ _changedData = true;
+ _data.putInt(i);
+ }
+
+ public void writeLong(long l) throws JMSException
+ {
+ checkWritable();
+ _changedData = true;
+ _data.putLong(l);
+ }
+
+ public void writeFloat(float v) throws JMSException
+ {
+ checkWritable();
+ _changedData = true;
+ _data.putFloat(v);
+ }
+
+ public void writeDouble(double v) throws JMSException
+ {
+ checkWritable();
+ _changedData = true;
+ _data.putDouble(v);
+ }
+
+ public void writeUTF(String string) throws JMSException
+ {
+ checkWritable();
+ try
+ {
+ CharsetEncoder encoder = Charset.forName("UTF-8").newEncoder();
+ java.nio.ByteBuffer encodedString = encoder.encode(CharBuffer.wrap(string));
+
+ _data.putShort((short)encodedString.limit());
+ _data.put(encodedString);
+ _changedData = true;
+ //_data.putString(string, Charset.forName("UTF-8").newEncoder());
+ // we must add the null terminator manually
+ //_data.put((byte)0);
+ }
+ catch (CharacterCodingException e)
+ {
+ JMSException ex = new JMSException("Unable to encode string: " + e);
+ ex.setLinkedException(e);
+ throw ex;
+ }
+ }
+
+ public void writeBytes(byte[] bytes) throws JMSException
+ {
+ checkWritable();
+ _data.put(bytes);
+ _changedData = true;
+ }
+
+ public void writeBytes(byte[] bytes, int offset, int length) throws JMSException
+ {
+ checkWritable();
+ _data.put(bytes, offset, length);
+ _changedData = true;
+ }
+
+ public void writeObject(Object object) throws JMSException
+ {
+ checkWritable();
+ if (object == null)
+ {
+ throw new NullPointerException("Argument must not be null");
+ }
+ Class clazz = object.getClass();
+ if (clazz == Byte.class)
+ {
+ writeByte((Byte) object);
+ }
+ else if (clazz == Boolean.class)
+ {
+ writeBoolean((Boolean) object);
+ }
+ else if (clazz == byte[].class)
+ {
+ writeBytes((byte[]) object);
+ }
+ else if (clazz == Short.class)
+ {
+ writeShort((Short) object);
+ }
+ else if (clazz == Character.class)
+ {
+ writeChar((Character) object);
+ }
+ else if (clazz == Integer.class)
+ {
+ writeInt((Integer) object);
+ }
+ else if (clazz == Long.class)
+ {
+ writeLong((Long) object);
+ }
+ else if (clazz == Float.class)
+ {
+ writeFloat((Float) object);
+ }
+ else if (clazz == Double.class)
+ {
+ writeDouble((Double) object);
+ }
+ else if (clazz == String.class)
+ {
+ writeUTF((String) object);
+ }
+ else
+ {
+ 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/Final/java/client/src/main/java/org/apache/qpid/client/message/JMSBytesMessageFactory.java b/Final/java/client/src/main/java/org/apache/qpid/client/message/JMSBytesMessageFactory.java
new file mode 100644
index 0000000000..fd2aae9feb
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/message/JMSBytesMessageFactory.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.client.message;
+
+import javax.jms.JMSException;
+
+import org.apache.mina.common.ByteBuffer;
+import org.apache.qpid.AMQException;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.framing.ContentHeaderBody;
+
+public class JMSBytesMessageFactory extends AbstractJMSMessageFactory
+{
+ protected AbstractJMSMessage createMessage(long deliveryTag, ByteBuffer data,
+ AMQShortString exchange, AMQShortString routingKey,
+ ContentHeaderBody contentHeader) throws AMQException
+ {
+ return new JMSBytesMessage(deliveryTag, contentHeader, exchange, routingKey, data);
+ }
+
+ public AbstractJMSMessage createMessage() throws JMSException
+ {
+ return new JMSBytesMessage();
+ }
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/client/message/JMSHeaderAdapter.java b/Final/java/client/src/main/java/org/apache/qpid/client/message/JMSHeaderAdapter.java
new file mode 100644
index 0000000000..39b4e1e27b
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/message/JMSHeaderAdapter.java
@@ -0,0 +1,552 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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 java.util.Enumeration;
+
+import javax.jms.JMSException;
+import javax.jms.MessageFormatException;
+
+import org.apache.mina.common.ByteBuffer;
+import org.apache.qpid.AMQPInvalidClassException;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.framing.FieldTable;
+
+
+public final class JMSHeaderAdapter
+{
+ private final FieldTable _headers;
+
+ public JMSHeaderAdapter(FieldTable headers)
+ {
+ _headers = headers;
+ }
+
+
+ public FieldTable getHeaders()
+ {
+ return _headers;
+ }
+
+ public boolean getBoolean(String string) throws JMSException
+ {
+ checkPropertyName(string);
+ Boolean b = getHeaders().getBoolean(string);
+
+ if (b == null)
+ {
+ if (getHeaders().containsKey(string))
+ {
+ Object str = getHeaders().getObject(string);
+
+ if (str == null || !(str instanceof String))
+ {
+ throw new MessageFormatException("getBoolean can't use " + string + " item.");
+ }
+ else
+ {
+ return Boolean.valueOf((String) str);
+ }
+ }
+ else
+ {
+ b = Boolean.valueOf(null);
+ }
+ }
+
+ return b;
+ }
+
+ public boolean getBoolean(AMQShortString string) throws JMSException
+ {
+ checkPropertyName(string);
+ Boolean b = getHeaders().getBoolean(string);
+
+ if (b == null)
+ {
+ if (getHeaders().containsKey(string))
+ {
+ Object str = getHeaders().getObject(string);
+
+ if (str == null || !(str instanceof String))
+ {
+ throw new MessageFormatException("getBoolean can't use " + string + " item.");
+ }
+ else
+ {
+ return Boolean.valueOf((String) str);
+ }
+ }
+ else
+ {
+ b = Boolean.valueOf(null);
+ }
+ }
+
+ return b;
+ }
+
+ public char getCharacter(String string) throws JMSException
+ {
+ checkPropertyName(string);
+ Character c = getHeaders().getCharacter(string);
+
+ if (c == null)
+ {
+ if (getHeaders().isNullStringValue(string))
+ {
+ throw new NullPointerException("Cannot convert null char");
+ }
+ else
+ {
+ throw new MessageFormatException("getChar can't use " + string + " item.");
+ }
+ }
+ else
+ {
+ return (char) c;
+ }
+ }
+
+ public byte[] getBytes(String string) throws JMSException
+ {
+ return getBytes(new AMQShortString(string));
+ }
+
+ public byte[] getBytes(AMQShortString string) throws JMSException
+ {
+ checkPropertyName(string);
+
+ byte[] bs = getHeaders().getBytes(string);
+
+ if (bs == null)
+ {
+ throw new MessageFormatException("getBytes can't use " + string + " item.");
+ }
+ else
+ {
+ return bs;
+ }
+ }
+
+ public byte getByte(String string) throws JMSException
+ {
+ checkPropertyName(string);
+ Byte b = getHeaders().getByte(string);
+ if (b == null)
+ {
+ if (getHeaders().containsKey(string))
+ {
+ Object str = getHeaders().getObject(string);
+
+ if (str == null || !(str instanceof String))
+ {
+ throw new MessageFormatException("getByte can't use " + string + " item.");
+ }
+ else
+ {
+ return Byte.valueOf((String) str);
+ }
+ }
+ else
+ {
+ b = Byte.valueOf(null);
+ }
+ }
+
+ return b;
+ }
+
+ public short getShort(String string) throws JMSException
+ {
+ checkPropertyName(string);
+ Short s = getHeaders().getShort(string);
+
+ if (s == null)
+ {
+ s = Short.valueOf(getByte(string));
+ }
+
+ return s;
+ }
+
+ public int getInteger(String string) throws JMSException
+ {
+ checkPropertyName(string);
+ Integer i = getHeaders().getInteger(string);
+
+ if (i == null)
+ {
+ i = Integer.valueOf(getShort(string));
+ }
+
+ return i;
+ }
+
+ public long getLong(String string) throws JMSException
+ {
+ checkPropertyName(string);
+ Long l = getHeaders().getLong(string);
+
+ if (l == null)
+ {
+ l = Long.valueOf(getInteger(string));
+ }
+
+ return l;
+ }
+
+ public float getFloat(String string) throws JMSException
+ {
+ checkPropertyName(string);
+ Float f = getHeaders().getFloat(string);
+
+ if (f == null)
+ {
+ if (getHeaders().containsKey(string))
+ {
+ Object str = getHeaders().getObject(string);
+
+ if (str == null || !(str instanceof String))
+ {
+ throw new MessageFormatException("getFloat can't use " + string + " item.");
+ }
+ else
+ {
+ return Float.valueOf((String) str);
+ }
+ }
+ else
+ {
+ f = Float.valueOf(null);
+ }
+
+ }
+
+ return f;
+ }
+
+ public double getDouble(String string) throws JMSException
+ {
+ checkPropertyName(string);
+ Double d = getHeaders().getDouble(string);
+
+ if (d == null)
+ {
+ d = Double.valueOf(getFloat(string));
+ }
+
+ return d;
+ }
+
+ public String getString(String string) throws JMSException
+ {
+ checkPropertyName(string);
+ String s = getHeaders().getString(string);
+
+ if (s == null)
+ {
+ if (getHeaders().containsKey(string))
+ {
+ Object o = getHeaders().getObject(string);
+ if (o instanceof byte[])
+ {
+ throw new MessageFormatException("getObject couldn't find " + string + " item.");
+ }
+ else
+ {
+ if (o == null)
+ {
+ return null;
+ }
+ else
+ {
+ s = String.valueOf(o);
+ }
+ }
+ }//else return s // null;
+ }
+
+ return s;
+ }
+
+ public Object getObject(String string) throws JMSException
+ {
+ checkPropertyName(string);
+ return getHeaders().getObject(string);
+ }
+
+ public void setBoolean(AMQShortString string, boolean b) throws JMSException
+ {
+ checkPropertyName(string);
+ getHeaders().setBoolean(string, b);
+ }
+
+ public void setBoolean(String string, boolean b) throws JMSException
+ {
+ checkPropertyName(string);
+ getHeaders().setBoolean(string, b);
+ }
+
+ public void setChar(String string, char c) throws JMSException
+ {
+ checkPropertyName(string);
+ getHeaders().setChar(string, c);
+ }
+
+ public Object setBytes(AMQShortString string, byte[] bytes)
+ {
+ checkPropertyName(string);
+ return getHeaders().setBytes(string, bytes);
+ }
+
+ public Object setBytes(String string, byte[] bytes)
+ {
+ checkPropertyName(string);
+ return getHeaders().setBytes(string, bytes);
+ }
+
+ public Object setBytes(String string, byte[] bytes, int start, int length)
+ {
+ checkPropertyName(string);
+ return getHeaders().setBytes(string, bytes, start, length);
+ }
+
+ public void setByte(String string, byte b) throws JMSException
+ {
+ checkPropertyName(string);
+ getHeaders().setByte(string, b);
+ }
+
+ public void setByte(AMQShortString string, byte b) throws JMSException
+ {
+ checkPropertyName(string);
+ getHeaders().setByte(string, b);
+ }
+
+
+ public void setShort(String string, short i) throws JMSException
+ {
+ checkPropertyName(string);
+ getHeaders().setShort(string, i);
+ }
+
+ public void setInteger(String string, int i) throws JMSException
+ {
+ checkPropertyName(string);
+ getHeaders().setInteger(string, i);
+ }
+
+ public void setInteger(AMQShortString string, int i) throws JMSException
+ {
+ checkPropertyName(string);
+ getHeaders().setInteger(string, i);
+ }
+
+ public void setLong(String string, long l) throws JMSException
+ {
+ checkPropertyName(string);
+ getHeaders().setLong(string, l);
+ }
+
+ public void setFloat(String string, float v) throws JMSException
+ {
+ checkPropertyName(string);
+ getHeaders().setFloat(string, v);
+ }
+
+ public void setDouble(String string, double v) throws JMSException
+ {
+ checkPropertyName(string);
+ getHeaders().setDouble(string, v);
+ }
+
+ public void setString(String string, String string1) throws JMSException
+ {
+ checkPropertyName(string);
+ getHeaders().setString(string, string1);
+ }
+
+ public void setString(AMQShortString string, String string1) throws JMSException
+ {
+ checkPropertyName(string);
+ getHeaders().setString(string, string1);
+ }
+
+ public void setObject(String string, Object object) throws JMSException
+ {
+ checkPropertyName(string);
+ try
+ {
+ getHeaders().setObject(string, object);
+ }
+ catch (AMQPInvalidClassException aice)
+ {
+ MessageFormatException mfe = new MessageFormatException("Only primatives are allowed object is:" + object.getClass());
+ mfe.setLinkedException(aice);
+ throw mfe;
+ }
+ }
+
+ public boolean itemExists(String string) throws JMSException
+ {
+ checkPropertyName(string);
+ return getHeaders().containsKey(string);
+ }
+
+ public Enumeration getPropertyNames()
+ {
+ return getHeaders().getPropertyNames();
+ }
+
+ public void clear()
+ {
+ getHeaders().clear();
+ }
+
+ public boolean propertyExists(AMQShortString propertyName)
+ {
+ checkPropertyName(propertyName);
+ return getHeaders().propertyExists(propertyName);
+ }
+
+ public boolean propertyExists(String propertyName)
+ {
+ checkPropertyName(propertyName);
+ return getHeaders().propertyExists(propertyName);
+ }
+
+ public Object put(Object key, Object value)
+ {
+ checkPropertyName(key.toString());
+ return getHeaders().setObject(key.toString(), value);
+ }
+
+ public Object remove(AMQShortString propertyName)
+ {
+ checkPropertyName(propertyName);
+ return getHeaders().remove(propertyName);
+ }
+
+ public Object remove(String propertyName)
+ {
+ checkPropertyName(propertyName);
+ return getHeaders().remove(propertyName);
+ }
+
+ public boolean isEmpty()
+ {
+ return getHeaders().isEmpty();
+ }
+
+ public void writeToBuffer(ByteBuffer data)
+ {
+ getHeaders().writeToBuffer(data);
+ }
+
+ public Enumeration getMapNames()
+ {
+ return getPropertyNames();
+ }
+
+ protected static void checkPropertyName(CharSequence propertyName)
+ {
+ if (propertyName == null)
+ {
+ throw new IllegalArgumentException("Property name must not be null");
+ }
+ else if (propertyName.length() == 0)
+ {
+ throw new IllegalArgumentException("Property name must not be the empty string");
+ }
+
+ checkIdentiferFormat(propertyName);
+ }
+
+ protected static void checkIdentiferFormat(CharSequence propertyName)
+ {
+// JMS requirements 3.5.1 Property Names
+// Identifiers:
+// - An identifier is an unlimited-length character sequence that must begin
+// with a Java identifier start character; all following characters must be Java
+// identifier part characters. An identifier start character is any character for
+// which the method Character.isJavaIdentifierStart returns true. This includes
+// '_' and '$'. An identifier part character is any character for which the
+// method Character.isJavaIdentifierPart returns true.
+// - Identifiers cannot be the names NULL, TRUE, or FALSE.
+// � Identifiers cannot be NOT, AND, OR, BETWEEN, LIKE, IN, IS, or
+// ESCAPE.
+// � Identifiers are either header field references or property references. The
+// type of a property value in a message selector corresponds to the type
+// used to set the property. If a property that does not exist in a message is
+// referenced, its value is NULL. The semantics of evaluating NULL values
+// in a selector are described in Section 3.8.1.2, �Null Values.�
+// � The conversions that apply to the get methods for properties do not
+// apply when a property is used in a message selector expression. For
+// example, suppose you set a property as a string value, as in the
+// following:
+// myMessage.setStringProperty("NumberOfOrders", "2");
+// The following expression in a message selector would evaluate to false,
+// because a string cannot be used in an arithmetic expression:
+// "NumberOfOrders > 1"
+// � Identifiers are case sensitive.
+// � Message header field references are restricted to JMSDeliveryMode,
+// JMSPriority, JMSMessageID, JMSTimestamp, JMSCorrelationID, and
+// JMSType. JMSMessageID, JMSCorrelationID, and JMSType values may be
+// null and if so are treated as a NULL value.
+
+ if (Boolean.getBoolean("strict-jms"))
+ {
+ // JMS start character
+ if (!(Character.isJavaIdentifierStart(propertyName.charAt(0))))
+ {
+ throw new IllegalArgumentException("Identifier '" + propertyName + "' does not start with a valid JMS identifier start character");
+ }
+
+ // JMS part character
+ int length = propertyName.length();
+ for (int c = 1; c < length; c++)
+ {
+ if (!(Character.isJavaIdentifierPart(propertyName.charAt(c))))
+ {
+ throw new IllegalArgumentException("Identifier '" + propertyName + "' contains an invalid JMS identifier character");
+ }
+ }
+
+ // JMS invalid names
+ if ((propertyName.equals("NULL")
+ || propertyName.equals("TRUE")
+ || propertyName.equals("FALSE")
+ || propertyName.equals("NOT")
+ || propertyName.equals("AND")
+ || propertyName.equals("OR")
+ || propertyName.equals("BETWEEN")
+ || propertyName.equals("LIKE")
+ || propertyName.equals("IN")
+ || propertyName.equals("IS")
+ || propertyName.equals("ESCAPE")))
+ {
+ throw new IllegalArgumentException("Identifier '" + propertyName + "' is not allowed in JMS");
+ }
+ }
+
+ }
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/client/message/JMSMapMessage.java b/Final/java/client/src/main/java/org/apache/qpid/client/message/JMSMapMessage.java
new file mode 100644
index 0000000000..a70acbabbe
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/message/JMSMapMessage.java
@@ -0,0 +1,507 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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.mina.common.ByteBuffer;
+
+import org.apache.qpid.AMQException;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.framing.ContentHeaderBody;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.jms.JMSException;
+import javax.jms.MessageFormatException;
+
+import java.nio.charset.CharacterCodingException;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+
+public class JMSMapMessage extends AbstractBytesTypedMessage implements javax.jms.MapMessage
+{
+ private static final Logger _logger = LoggerFactory.getLogger(JMSMapMessage.class);
+
+ public static final String MIME_TYPE = "jms/map-message";
+ private static final AMQShortString MIME_TYPE_SHORT_STRING = new AMQShortString(MIME_TYPE);
+
+ private Map<String, Object> _map = new HashMap<String, Object>();
+
+ public JMSMapMessage() throws JMSException
+ {
+ this(null);
+ }
+
+ JMSMapMessage(ByteBuffer data) throws JMSException
+ {
+ super(data); // this instantiates a content header
+ populateMapFromData();
+ }
+
+ JMSMapMessage(long messageNbr, ContentHeaderBody contentHeader, AMQShortString exchange, AMQShortString routingKey,
+ ByteBuffer data) throws AMQException
+ {
+ super(messageNbr, contentHeader, exchange, routingKey, data);
+ try
+ {
+ populateMapFromData();
+ }
+ catch (JMSException je)
+ {
+ throw new AMQException("Error populating MapMessage from ByteBuffer", je);
+
+ }
+
+ }
+
+ public String toBodyString() throws JMSException
+ {
+ return _map.toString();
+ }
+
+ public AMQShortString getMimeTypeAsShortString()
+ {
+ return MIME_TYPE_SHORT_STRING;
+ }
+
+ public ByteBuffer getData()
+ {
+ // What if _data is null?
+ writeMapToData();
+
+ return super.getData();
+ }
+
+ @Override
+ public void clearBodyImpl() throws JMSException
+ {
+ super.clearBodyImpl();
+ _map.clear();
+ }
+
+ public boolean getBoolean(String propName) throws JMSException
+ {
+ Object value = _map.get(propName);
+
+ if (value instanceof Boolean)
+ {
+ return ((Boolean) value).booleanValue();
+ }
+ else if ((value instanceof String) || (value == null))
+ {
+ return Boolean.valueOf((String) value);
+ }
+ else
+ {
+ throw new MessageFormatException("Property " + propName + " of type " + value.getClass().getName()
+ + " cannot be converted to boolean.");
+ }
+
+ }
+
+ public byte getByte(String propName) throws JMSException
+ {
+ Object value = _map.get(propName);
+
+ if (value instanceof Byte)
+ {
+ return ((Byte) value).byteValue();
+ }
+ else if ((value instanceof String) || (value == null))
+ {
+ return Byte.valueOf((String) value).byteValue();
+ }
+ else
+ {
+ throw new MessageFormatException("Property " + propName + " of type " + value.getClass().getName()
+ + " cannot be converted to byte.");
+ }
+ }
+
+ public short getShort(String propName) throws JMSException
+ {
+ Object value = _map.get(propName);
+
+ if (value instanceof Short)
+ {
+ return ((Short) value).shortValue();
+ }
+ else if (value instanceof Byte)
+ {
+ return ((Byte) value).shortValue();
+ }
+ else if ((value instanceof String) || (value == null))
+ {
+ return Short.valueOf((String) value).shortValue();
+ }
+ else
+ {
+ throw new MessageFormatException("Property " + propName + " of type " + value.getClass().getName()
+ + " cannot be converted to short.");
+ }
+
+ }
+
+ public int getInt(String propName) throws JMSException
+ {
+ Object value = _map.get(propName);
+
+ if (value instanceof Integer)
+ {
+ return ((Integer) value).intValue();
+ }
+ else if (value instanceof Short)
+ {
+ return ((Short) value).intValue();
+ }
+ else if (value instanceof Byte)
+ {
+ return ((Byte) value).intValue();
+ }
+ else if ((value instanceof String) || (value == null))
+ {
+ return Integer.valueOf((String) value).intValue();
+ }
+ else
+ {
+ throw new MessageFormatException("Property " + propName + " of type " + value.getClass().getName()
+ + " cannot be converted to int.");
+ }
+
+ }
+
+ public long getLong(String propName) throws JMSException
+ {
+ Object value = _map.get(propName);
+
+ if (value instanceof Long)
+ {
+ return ((Long) value).longValue();
+ }
+ else if (value instanceof Integer)
+ {
+ return ((Integer) value).longValue();
+ }
+
+ if (value instanceof Short)
+ {
+ return ((Short) value).longValue();
+ }
+
+ if (value instanceof Byte)
+ {
+ return ((Byte) value).longValue();
+ }
+ else if ((value instanceof String) || (value == null))
+ {
+ return Long.valueOf((String) value).longValue();
+ }
+ else
+ {
+ throw new MessageFormatException("Property " + propName + " of type " + value.getClass().getName()
+ + " cannot be converted to long.");
+ }
+
+ }
+
+ public char getChar(String propName) throws JMSException
+ {
+ Object value = _map.get(propName);
+
+ if (!_map.containsKey(propName))
+ {
+ throw new MessageFormatException("Property " + propName + " not present");
+ }
+ else if (value instanceof Character)
+ {
+ return ((Character) value).charValue();
+ }
+ else if (value == null)
+ {
+ throw new NullPointerException("Property " + propName + " has null value and therefore cannot "
+ + "be converted to char.");
+ }
+ else
+ {
+ throw new MessageFormatException("Property " + propName + " of type " + value.getClass().getName()
+ + " cannot be converted to boolan.");
+ }
+
+ }
+
+ public float getFloat(String propName) throws JMSException
+ {
+ Object value = _map.get(propName);
+
+ if (value instanceof Float)
+ {
+ return ((Float) value).floatValue();
+ }
+ else if ((value instanceof String) || (value == null))
+ {
+ return Float.valueOf((String) value).floatValue();
+ }
+ else
+ {
+ throw new MessageFormatException("Property " + propName + " of type " + value.getClass().getName()
+ + " cannot be converted to float.");
+ }
+ }
+
+ public double getDouble(String propName) throws JMSException
+ {
+ Object value = _map.get(propName);
+
+ if (value instanceof Double)
+ {
+ return ((Double) value).doubleValue();
+ }
+ else if (value instanceof Float)
+ {
+ return ((Float) value).doubleValue();
+ }
+ else if ((value instanceof String) || (value == null))
+ {
+ return Double.valueOf((String) value).doubleValue();
+ }
+ else
+ {
+ throw new MessageFormatException("Property " + propName + " of type " + value.getClass().getName()
+ + " cannot be converted to double.");
+ }
+ }
+
+ public String getString(String propName) throws JMSException
+ {
+ Object value = _map.get(propName);
+
+ if ((value instanceof String) || (value == null))
+ {
+ return (String) value;
+ }
+ else if (value instanceof byte[])
+ {
+ throw new MessageFormatException("Property " + propName + " of type byte[] " + "cannot be converted to String.");
+ }
+ else
+ {
+ return value.toString();
+ }
+
+ }
+
+ public byte[] getBytes(String propName) throws JMSException
+ {
+ Object value = _map.get(propName);
+
+ if (!_map.containsKey(propName))
+ {
+ throw new MessageFormatException("Property " + propName + " not present");
+ }
+ else if ((value instanceof byte[]) || (value == null))
+ {
+ return (byte[]) value;
+ }
+ else
+ {
+ throw new MessageFormatException("Property " + propName + " of type " + value.getClass().getName()
+ + " cannot be converted to byte[].");
+ }
+ }
+
+ public Object getObject(String propName) throws JMSException
+ {
+ return _map.get(propName);
+ }
+
+ public Enumeration getMapNames() throws JMSException
+ {
+ return Collections.enumeration(_map.keySet());
+ }
+
+ public void setBoolean(String propName, boolean b) throws JMSException
+ {
+ checkWritable();
+ checkPropertyName(propName);
+ _map.put(propName, b);
+ }
+
+ public void setByte(String propName, byte b) throws JMSException
+ {
+ checkWritable();
+ checkPropertyName(propName);
+ _map.put(propName, b);
+ }
+
+ public void setShort(String propName, short i) throws JMSException
+ {
+ checkWritable();
+ checkPropertyName(propName);
+ _map.put(propName, i);
+ }
+
+ public void setChar(String propName, char c) throws JMSException
+ {
+ checkWritable();
+ checkPropertyName(propName);
+ _map.put(propName, c);
+ }
+
+ public void setInt(String propName, int i) throws JMSException
+ {
+ checkWritable();
+ checkPropertyName(propName);
+ _map.put(propName, i);
+ }
+
+ public void setLong(String propName, long l) throws JMSException
+ {
+ checkWritable();
+ checkPropertyName(propName);
+ _map.put(propName, l);
+ }
+
+ public void setFloat(String propName, float v) throws JMSException
+ {
+ checkWritable();
+ checkPropertyName(propName);
+ _map.put(propName, v);
+ }
+
+ public void setDouble(String propName, double v) throws JMSException
+ {
+ checkWritable();
+ checkPropertyName(propName);
+ _map.put(propName, v);
+ }
+
+ public void setString(String propName, String string1) throws JMSException
+ {
+ checkWritable();
+ checkPropertyName(propName);
+ _map.put(propName, string1);
+ }
+
+ public void setBytes(String propName, byte[] bytes) throws JMSException
+ {
+ checkWritable();
+ checkPropertyName(propName);
+ _map.put(propName, bytes);
+ }
+
+ public void setBytes(String propName, byte[] bytes, int offset, int length) throws JMSException
+ {
+ if ((offset == 0) && (length == bytes.length))
+ {
+ setBytes(propName, bytes);
+ }
+ else
+ {
+ byte[] newBytes = new byte[length];
+ System.arraycopy(bytes, offset, newBytes, 0, length);
+ setBytes(propName, newBytes);
+ }
+ }
+
+ public void setObject(String propName, Object value) throws JMSException
+ {
+ checkWritable();
+ checkPropertyName(propName);
+ if ((value instanceof Boolean) || (value instanceof Byte) || (value instanceof Short) || (value instanceof Integer)
+ || (value instanceof Long) || (value instanceof Character) || (value instanceof Float)
+ || (value instanceof Double) || (value instanceof String) || (value instanceof byte[]) || (value == null))
+ {
+ _map.put(propName, value);
+ }
+ else
+ {
+ throw new MessageFormatException("Cannot set property " + propName + " to value " + value + "of type "
+ + value.getClass().getName() + ".");
+ }
+ }
+
+ private void checkPropertyName(String propName)
+ {
+ if ((propName == null) || propName.equals(""))
+ {
+ throw new IllegalArgumentException("Property name cannot be null, or the empty String.");
+ }
+ }
+
+ public boolean itemExists(String propName) throws JMSException
+ {
+ return _map.containsKey(propName);
+ }
+
+ private void populateMapFromData() throws JMSException
+ {
+ if (_data != null)
+ {
+ _data.rewind();
+
+ final int entries = readIntImpl();
+ for (int i = 0; i < entries; i++)
+ {
+ String propName = readStringImpl();
+ Object value = readObject();
+ _map.put(propName, value);
+ }
+ }
+ else
+ {
+ _map.clear();
+ }
+ }
+
+ private void writeMapToData()
+ {
+ allocateInitialBuffer();
+ final int size = _map.size();
+ writeIntImpl(size);
+ for (Map.Entry<String, Object> entry : _map.entrySet())
+ {
+ try
+ {
+ writeStringImpl(entry.getKey());
+ }
+ catch (CharacterCodingException e)
+ {
+ throw new IllegalArgumentException("Cannot encode property key name " + entry.getKey(), e);
+
+ }
+
+ try
+ {
+ writeObject(entry.getValue());
+ }
+ catch (JMSException e)
+ {
+ Object value = entry.getValue();
+ throw new IllegalArgumentException("Cannot encode property key name " + entry.getKey() + " value : " + value
+ + " (type: " + value.getClass().getName() + ").", e);
+ }
+ }
+
+ }
+
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/client/message/JMSMapMessageFactory.java b/Final/java/client/src/main/java/org/apache/qpid/client/message/JMSMapMessageFactory.java
new file mode 100644
index 0000000000..a6b9bb29a4
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/message/JMSMapMessageFactory.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.client.message;
+
+import javax.jms.JMSException;
+
+import org.apache.mina.common.ByteBuffer;
+import org.apache.qpid.AMQException;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.framing.ContentHeaderBody;
+
+public class JMSMapMessageFactory extends AbstractJMSMessageFactory
+{
+ public AbstractJMSMessage createMessage() throws JMSException
+ {
+ return new JMSMapMessage();
+ }
+
+ protected AbstractJMSMessage createMessage(long deliveryTag, ByteBuffer data,
+ AMQShortString exchange, AMQShortString routingKey,
+ ContentHeaderBody contentHeader) throws AMQException
+ {
+ return new JMSMapMessage(deliveryTag, contentHeader, exchange, routingKey, data);
+ }
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/client/message/JMSObjectMessage.java b/Final/java/client/src/main/java/org/apache/qpid/client/message/JMSObjectMessage.java
new file mode 100644
index 0000000000..caf8741280
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/message/JMSObjectMessage.java
@@ -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.
+ *
+ */
+package org.apache.qpid.client.message;
+
+import java.io.IOException;
+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;
+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;
+import org.apache.qpid.framing.ContentHeaderBody;
+
+public class JMSObjectMessage extends AbstractJMSMessage implements ObjectMessage
+{
+ public static final String MIME_TYPE = "application/java-object-stream";
+ private static final AMQShortString MIME_TYPE_SHORT_STRING = new AMQShortString(MIME_TYPE);
+
+ private static final int DEFAULT_BUFFER_SIZE = 1024;
+
+ /**
+ * Creates empty, writable message for use by producers
+ */
+ public JMSObjectMessage()
+ {
+ this(null);
+ }
+
+ private JMSObjectMessage(ByteBuffer data)
+ {
+ super(data);
+ if (data == null)
+ {
+ _data = ByteBuffer.allocate(DEFAULT_BUFFER_SIZE);
+ _data.setAutoExpand(true);
+ }
+
+ getContentHeaderProperties().setContentType(MIME_TYPE_SHORT_STRING);
+ }
+
+ /**
+ * Creates read only message for delivery to consumers
+ */
+ JMSObjectMessage(long messageNbr, ContentHeaderBody contentHeader, AMQShortString exchange, AMQShortString routingKey,
+ ByteBuffer data) throws AMQException
+ {
+ super(messageNbr, (BasicContentHeaderProperties) contentHeader.properties, exchange, routingKey, data);
+ }
+
+ public void clearBodyImpl() throws JMSException
+ {
+ if (_data != null)
+ {
+ _data.release();
+ }
+
+ _data = null;
+
+ }
+
+ public String toBodyString() throws JMSException
+ {
+ return toString(_data);
+ }
+
+ public AMQShortString getMimeTypeAsShortString()
+ {
+ return MIME_TYPE_SHORT_STRING;
+ }
+
+ public void setObject(Serializable serializable) throws JMSException
+ {
+ checkWritable();
+
+ if (_data == null)
+ {
+ _data = ByteBuffer.allocate(DEFAULT_BUFFER_SIZE);
+ _data.setAutoExpand(true);
+ }
+ else
+ {
+ _data.rewind();
+ }
+
+ try
+ {
+ ObjectOutputStream out = new ObjectOutputStream(_data.asOutputStream());
+ out.writeObject(serializable);
+ out.flush();
+ out.close();
+ }
+ catch (IOException e)
+ {
+ MessageFormatException mfe = new MessageFormatException("Message not serializable: " + e);
+ mfe.setLinkedException(e);
+ throw mfe;
+ }
+
+ }
+
+ public Serializable getObject() throws JMSException
+ {
+ ObjectInputStream in = null;
+ if (_data == null)
+ {
+ return null;
+ }
+
+ try
+ {
+ _data.rewind();
+ in = new ObjectInputStream(_data.asInputStream());
+
+ return (Serializable) in.readObject();
+ }
+ catch (IOException e)
+ {
+ MessageFormatException mfe = new MessageFormatException("Could not deserialize message: " + e);
+ mfe.setLinkedException(e);
+ throw mfe;
+ }
+ catch (ClassNotFoundException e)
+ {
+ MessageFormatException mfe = new MessageFormatException("Could not deserialize message: " + e);
+ mfe.setLinkedException(e);
+ throw mfe;
+ }
+ finally
+ {
+ _data.rewind();
+ close(in);
+ }
+ }
+
+ private static void close(InputStream in)
+ {
+ try
+ {
+ if (in != null)
+ {
+ in.close();
+ }
+ }
+ catch (IOException ignore)
+ { }
+ }
+
+ private static String toString(ByteBuffer data)
+ {
+ if (data == null)
+ {
+ return null;
+ }
+
+ int pos = data.position();
+ try
+ {
+ return data.getString(Charset.forName("UTF8").newDecoder());
+ }
+ catch (CharacterCodingException e)
+ {
+ return null;
+ }
+ finally
+ {
+ data.position(pos);
+ }
+ }
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/client/message/JMSObjectMessageFactory.java b/Final/java/client/src/main/java/org/apache/qpid/client/message/JMSObjectMessageFactory.java
new file mode 100644
index 0000000000..57ac4fb006
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/message/JMSObjectMessageFactory.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.client.message;
+
+import javax.jms.JMSException;
+
+import org.apache.mina.common.ByteBuffer;
+import org.apache.qpid.AMQException;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.framing.ContentHeaderBody;
+
+public class JMSObjectMessageFactory extends AbstractJMSMessageFactory
+{
+ protected AbstractJMSMessage createMessage(long deliveryTag, ByteBuffer data,
+ AMQShortString exchange, AMQShortString routingKey,
+ ContentHeaderBody contentHeader) throws AMQException
+ {
+ return new JMSObjectMessage(deliveryTag, contentHeader, exchange, routingKey, data);
+ }
+
+ public AbstractJMSMessage createMessage() throws JMSException
+ {
+ return new JMSObjectMessage();
+ }
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/client/message/JMSStreamMessage.java b/Final/java/client/src/main/java/org/apache/qpid/client/message/JMSStreamMessage.java
new file mode 100644
index 0000000000..b4350c7a98
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/message/JMSStreamMessage.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.client.message;
+
+import javax.jms.JMSException;
+import javax.jms.StreamMessage;
+
+import org.apache.mina.common.ByteBuffer;
+import org.apache.qpid.AMQException;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.framing.ContentHeaderBody;
+
+/**
+ * @author Apache Software Foundation
+ */
+public class JMSStreamMessage extends AbstractBytesTypedMessage implements StreamMessage
+{
+ public static final String MIME_TYPE="jms/stream-message";
+ private static final AMQShortString MIME_TYPE_SHORT_STRING = new AMQShortString(MIME_TYPE);
+
+
+ /**
+ * This is set when reading a byte array. The readBytes(byte[]) method supports multiple calls to read
+ * a byte array in multiple chunks, hence this is used to track how much is left to be read
+ */
+ private int _byteArrayRemaining = -1;
+
+ public JMSStreamMessage()
+ {
+ this(null);
+ }
+
+ /**
+ * Construct a stream message with existing data.
+ *
+ * @param data the data that comprises this message. If data is null, you get a 1024 byte buffer that is
+ * set to auto expand
+ */
+ JMSStreamMessage(ByteBuffer data)
+ {
+ super(data); // this instanties a content header
+ }
+
+
+ JMSStreamMessage(long messageNbr, ContentHeaderBody contentHeader, AMQShortString exchange,
+ AMQShortString routingKey, ByteBuffer data) throws AMQException
+ {
+ super(messageNbr, contentHeader, exchange, routingKey, data);
+ }
+
+ public void reset()
+ {
+ super.reset();
+ _readableMessage = true;
+ }
+
+ public AMQShortString getMimeTypeAsShortString()
+ {
+ return MIME_TYPE_SHORT_STRING;
+ }
+
+
+
+ public boolean readBoolean() throws JMSException
+ {
+ return super.readBoolean();
+ }
+
+
+ public byte readByte() throws JMSException
+ {
+ return super.readByte();
+ }
+
+ public short readShort() throws JMSException
+ {
+ return super.readShort();
+ }
+
+ /**
+ * Note that this method reads a unicode character as two bytes from the stream
+ *
+ * @return the character read from the stream
+ * @throws JMSException
+ */
+ public char readChar() throws JMSException
+ {
+ return super.readChar();
+ }
+
+ public int readInt() throws JMSException
+ {
+ return super.readInt();
+ }
+
+ public long readLong() throws JMSException
+ {
+ return super.readLong();
+ }
+
+ public float readFloat() throws JMSException
+ {
+ return super.readFloat();
+ }
+
+ public double readDouble() throws JMSException
+ {
+ return super.readDouble();
+ }
+
+ public String readString() throws JMSException
+ {
+ return super.readString();
+ }
+
+ public int readBytes(byte[] bytes) throws JMSException
+ {
+ return super.readBytes(bytes);
+ }
+
+
+ public Object readObject() throws JMSException
+ {
+ return super.readObject();
+ }
+
+ public void writeBoolean(boolean b) throws JMSException
+ {
+ super.writeBoolean(b);
+ }
+
+ public void writeByte(byte b) throws JMSException
+ {
+ super.writeByte(b);
+ }
+
+ public void writeShort(short i) throws JMSException
+ {
+ super.writeShort(i);
+ }
+
+ public void writeChar(char c) throws JMSException
+ {
+ super.writeChar(c);
+ }
+
+ public void writeInt(int i) throws JMSException
+ {
+ super.writeInt(i);
+ }
+
+ public void writeLong(long l) throws JMSException
+ {
+ super.writeLong(l);
+ }
+
+ public void writeFloat(float v) throws JMSException
+ {
+ super.writeFloat(v);
+ }
+
+ public void writeDouble(double v) throws JMSException
+ {
+ super.writeDouble(v);
+ }
+
+ public void writeString(String string) throws JMSException
+ {
+ super.writeString(string);
+ }
+
+ public void writeBytes(byte[] bytes) throws JMSException
+ {
+ super.writeBytes(bytes);
+ }
+
+ public void writeBytes(byte[] bytes, int offset, int length) throws JMSException
+ {
+ super.writeBytes(bytes,offset,length);
+ }
+
+ public void writeObject(Object object) throws JMSException
+ {
+ super.writeObject(object);
+ }
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/client/message/JMSStreamMessageFactory.java b/Final/java/client/src/main/java/org/apache/qpid/client/message/JMSStreamMessageFactory.java
new file mode 100644
index 0000000000..c34ee7175d
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/message/JMSStreamMessageFactory.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.client.message;
+
+import javax.jms.JMSException;
+
+import org.apache.mina.common.ByteBuffer;
+import org.apache.qpid.AMQException;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.framing.ContentHeaderBody;
+
+public class JMSStreamMessageFactory extends AbstractJMSMessageFactory
+{
+ protected AbstractJMSMessage createMessage(long deliveryTag, ByteBuffer data,
+ AMQShortString exchange, AMQShortString routingKey,
+ ContentHeaderBody contentHeader) throws AMQException
+ {
+ return new JMSStreamMessage(deliveryTag, contentHeader, exchange, routingKey, data);
+ }
+
+ public AbstractJMSMessage createMessage() throws JMSException
+ {
+ return new JMSStreamMessage();
+ }
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/client/message/JMSTextMessage.java b/Final/java/client/src/main/java/org/apache/qpid/client/message/JMSTextMessage.java
new file mode 100644
index 0000000000..87cc80f21d
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/message/JMSTextMessage.java
@@ -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.
+ *
+ */
+package org.apache.qpid.client.message;
+
+import java.io.UnsupportedEncodingException;
+import java.nio.charset.CharacterCodingException;
+import java.nio.charset.Charset;
+
+import javax.jms.JMSException;
+
+import org.apache.mina.common.ByteBuffer;
+import org.apache.qpid.AMQException;
+import org.apache.qpid.client.CustomJMSXProperty;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.framing.BasicContentHeaderProperties;
+
+public class JMSTextMessage extends AbstractJMSMessage implements javax.jms.TextMessage
+{
+ private static final String MIME_TYPE = "text/plain";
+ private static final AMQShortString MIME_TYPE_SHORT_STRING = new AMQShortString(MIME_TYPE);
+
+
+ private String _decodedValue;
+
+ /**
+ * This constant represents the name of a property that is set when the message payload is null.
+ */
+ private static final AMQShortString PAYLOAD_NULL_PROPERTY = CustomJMSXProperty.JMS_AMQP_NULL.getShortStringName();
+ private static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
+
+ public JMSTextMessage() throws JMSException
+ {
+ this(null, null);
+ }
+
+ JMSTextMessage(ByteBuffer data, String encoding) throws JMSException
+ {
+ super(data); // this instantiates a content header
+ getContentHeaderProperties().setContentType(MIME_TYPE_SHORT_STRING);
+ getContentHeaderProperties().setEncoding(encoding);
+ }
+
+ JMSTextMessage(long deliveryTag, BasicContentHeaderProperties contentHeader, AMQShortString exchange,
+ AMQShortString routingKey, ByteBuffer data)
+ throws AMQException
+ {
+ super(deliveryTag, contentHeader, exchange, routingKey, data);
+ contentHeader.setContentType(MIME_TYPE_SHORT_STRING);
+ _data = data;
+ }
+
+ JMSTextMessage(ByteBuffer data) throws JMSException
+ {
+ this(data, null);
+ }
+
+ JMSTextMessage(String text) throws JMSException
+ {
+ super((ByteBuffer) null);
+ setText(text);
+ }
+
+ public void clearBodyImpl() throws JMSException
+ {
+ if (_data != null)
+ {
+ _data.release();
+ }
+ _data = null;
+ _decodedValue = null;
+ }
+
+ public String toBodyString() throws JMSException
+ {
+ return getText();
+ }
+
+ public void setData(ByteBuffer data)
+ {
+ _data = data;
+ }
+
+ public AMQShortString getMimeTypeAsShortString()
+ {
+ return MIME_TYPE_SHORT_STRING;
+ }
+
+ public void setText(String text) throws JMSException
+ {
+ checkWritable();
+
+ clearBody();
+ try
+ {
+ if (text != null)
+ {
+ _data = ByteBuffer.allocate(text.length());
+ _data.limit(text.length()) ;
+ //_data.sweep();
+ _data.setAutoExpand(true);
+ final String encoding = getContentHeaderProperties().getEncodingAsString();
+ if (encoding == null)
+ {
+ _data.put(text.getBytes(DEFAULT_CHARSET.name()));
+ }
+ else
+ {
+ _data.put(text.getBytes(encoding));
+ }
+ _changedData=true;
+ }
+ _decodedValue = text;
+ }
+ catch (UnsupportedEncodingException e)
+ {
+ // should never occur
+ JMSException jmse = new JMSException("Unable to decode text data");
+ jmse.setLinkedException(e);
+ }
+ }
+
+ public String getText() throws JMSException
+ {
+ if (_data == null && _decodedValue == null)
+ {
+ return null;
+ }
+ else if (_decodedValue != null)
+ {
+ return _decodedValue;
+ }
+ else
+ {
+ _data.rewind();
+
+ if (propertyExists(PAYLOAD_NULL_PROPERTY) && getBooleanProperty(PAYLOAD_NULL_PROPERTY))
+ {
+ return null;
+ }
+ if (getContentHeaderProperties().getEncodingAsString() != null)
+ {
+ try
+ {
+ _decodedValue = _data.getString(Charset.forName(getContentHeaderProperties().getEncodingAsString()).newDecoder());
+ }
+ catch (CharacterCodingException e)
+ {
+ JMSException je = new JMSException("Could not decode string data: " + e);
+ je.setLinkedException(e);
+ throw je;
+ }
+ }
+ else
+ {
+ try
+ {
+ _decodedValue = _data.getString(DEFAULT_CHARSET.newDecoder());
+ }
+ catch (CharacterCodingException e)
+ {
+ JMSException je = new JMSException("Could not decode string data: " + e);
+ je.setLinkedException(e);
+ throw je;
+ }
+ }
+ return _decodedValue;
+ }
+ }
+
+ @Override
+ public void prepareForSending() throws JMSException
+ {
+ super.prepareForSending();
+ if (_data == null)
+ {
+ setBooleanProperty(PAYLOAD_NULL_PROPERTY, true);
+ }
+ else
+ {
+ removeProperty(PAYLOAD_NULL_PROPERTY);
+ }
+ }
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/client/message/JMSTextMessageFactory.java b/Final/java/client/src/main/java/org/apache/qpid/client/message/JMSTextMessageFactory.java
new file mode 100644
index 0000000000..c5942dbe2a
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/message/JMSTextMessageFactory.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.client.message;
+
+import javax.jms.JMSException;
+
+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.ContentHeaderBody;
+
+public class JMSTextMessageFactory extends AbstractJMSMessageFactory
+{
+
+ public AbstractJMSMessage createMessage() throws JMSException
+ {
+ return new JMSTextMessage();
+ }
+
+ protected AbstractJMSMessage createMessage(long deliveryTag, ByteBuffer data,
+ AMQShortString exchange, AMQShortString routingKey,
+ ContentHeaderBody contentHeader) throws AMQException
+ {
+ return new JMSTextMessage(deliveryTag, (BasicContentHeaderProperties) contentHeader.properties,
+ exchange, routingKey, data);
+ }
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/client/message/MessageConverter.java b/Final/java/client/src/main/java/org/apache/qpid/client/message/MessageConverter.java
new file mode 100644
index 0000000000..f6b11c6f6c
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/message/MessageConverter.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.client.message;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.jms.BytesMessage;
+import javax.jms.JMSException;
+import javax.jms.MapMessage;
+import javax.jms.Message;
+import javax.jms.MessageEOFException;
+import javax.jms.ObjectMessage;
+import javax.jms.StreamMessage;
+import javax.jms.TextMessage;
+
+import java.util.Enumeration;
+
+public class MessageConverter
+{
+
+ /**
+ * Log4J logger
+ */
+ protected final Logger _logger = LoggerFactory.getLogger(getClass());
+
+ /**
+ * AbstractJMSMessage which will hold the converted message
+ */
+ private AbstractJMSMessage _newMessage;
+
+ public MessageConverter(AbstractJMSMessage message) throws JMSException
+ {
+ _newMessage = message;
+ }
+
+ public MessageConverter(BytesMessage message) throws JMSException
+ {
+ BytesMessage bytesMessage = (BytesMessage) message;
+ bytesMessage.reset();
+
+ JMSBytesMessage nativeMsg = new JMSBytesMessage();
+
+ byte[] buf = new byte[1024];
+
+ int len;
+
+ while ((len = bytesMessage.readBytes(buf)) != -1)
+ {
+ nativeMsg.writeBytes(buf, 0, len);
+ }
+
+ _newMessage = nativeMsg;
+ setMessageProperties(message);
+ }
+
+ public MessageConverter(MapMessage message) throws JMSException
+ {
+ MapMessage nativeMessage = new JMSMapMessage();
+
+ Enumeration mapNames = message.getMapNames();
+ while (mapNames.hasMoreElements())
+ {
+ String name = (String) mapNames.nextElement();
+ nativeMessage.setObject(name, message.getObject(name));
+ }
+
+ _newMessage = (AbstractJMSMessage) nativeMessage;
+ setMessageProperties(message);
+ }
+
+ public MessageConverter(ObjectMessage message) throws JMSException
+ {
+ ObjectMessage origMessage = (ObjectMessage) message;
+ ObjectMessage nativeMessage = new JMSObjectMessage();
+
+ nativeMessage.setObject(origMessage.getObject());
+
+ _newMessage = (AbstractJMSMessage) nativeMessage;
+ setMessageProperties(message);
+
+ }
+
+ public MessageConverter(TextMessage message) throws JMSException
+ {
+ TextMessage nativeMessage = new JMSTextMessage();
+
+ nativeMessage.setText(message.getText());
+
+ _newMessage = (AbstractJMSMessage) nativeMessage;
+ setMessageProperties(message);
+ }
+
+ public MessageConverter(StreamMessage message) throws JMSException
+ {
+ StreamMessage nativeMessage = new JMSStreamMessage();
+
+ try
+ {
+ message.reset();
+ while (true)
+ {
+ nativeMessage.writeObject(message.readObject());
+ }
+ }
+ catch (MessageEOFException e)
+ {
+ // we're at the end so don't mind the exception
+ }
+
+ _newMessage = (AbstractJMSMessage) nativeMessage;
+ setMessageProperties(message);
+ }
+
+ public MessageConverter(Message message) throws JMSException
+ {
+ // Send a message with just properties.
+ // Throwing away content
+ BytesMessage nativeMessage = new JMSBytesMessage();
+
+ _newMessage = (AbstractJMSMessage) nativeMessage;
+ setMessageProperties(message);
+ }
+
+ public AbstractJMSMessage getConvertedMessage()
+ {
+ return _newMessage;
+ }
+
+ /**
+ * Sets all message properties
+ */
+ protected void setMessageProperties(Message message) throws JMSException
+ {
+ setNonJMSProperties(message);
+ setJMSProperties(message);
+ }
+
+ /**
+ * Sets all non-JMS defined properties on converted message
+ */
+ protected void setNonJMSProperties(Message message) throws JMSException
+ {
+ Enumeration propertyNames = message.getPropertyNames();
+ while (propertyNames.hasMoreElements())
+ {
+ String propertyName = String.valueOf(propertyNames.nextElement());
+ // TODO: Shouldn't need to check for JMS properties here as don't think getPropertyNames() should return them
+ if (!propertyName.startsWith("JMSX_"))
+ {
+ Object value = message.getObjectProperty(propertyName);
+ _newMessage.setObjectProperty(propertyName, value);
+ }
+ }
+ }
+
+ /**
+ * Exposed JMS defined properties on converted message:
+ * JMSDestination - we don't set here
+ * JMSDeliveryMode - set
+ * JMSExpiration - we don't set here
+ * JMSPriority - we don't set here
+ * JMSMessageID - we don't set here
+ * JMSTimestamp - we don't set here
+ * JMSCorrelationID - set
+ * JMSReplyTo - set
+ * JMSType - set
+ * JMSRedlivered - we don't set here
+ */
+ protected void setJMSProperties(Message message) throws JMSException
+ {
+ _newMessage.setJMSDeliveryMode(message.getJMSDeliveryMode());
+
+ if (message.getJMSReplyTo() != null)
+ {
+ _newMessage.setJMSReplyTo(message.getJMSReplyTo());
+ }
+
+ _newMessage.setJMSType(message.getJMSType());
+
+ _newMessage.setJMSCorrelationID(message.getJMSCorrelationID());
+ }
+
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/client/message/MessageFactory.java b/Final/java/client/src/main/java/org/apache/qpid/client/message/MessageFactory.java
new file mode 100644
index 0000000000..0fe4af715d
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/message/MessageFactory.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.client.message;
+
+import java.util.List;
+
+import javax.jms.JMSException;
+
+import org.apache.qpid.AMQException;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.framing.ContentHeaderBody;
+
+
+public interface MessageFactory
+{
+ AbstractJMSMessage createMessage(long deliveryTag, boolean redelivered,
+ ContentHeaderBody contentHeader,
+ AMQShortString exchange, AMQShortString routingKey,
+ List bodies)
+ throws JMSException, AMQException;
+
+ AbstractJMSMessage createMessage() throws JMSException;
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/client/message/MessageFactoryRegistry.java b/Final/java/client/src/main/java/org/apache/qpid/client/message/MessageFactoryRegistry.java
new file mode 100644
index 0000000000..c2015f9e7c
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/message/MessageFactoryRegistry.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.client.message;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.jms.JMSException;
+
+import org.apache.qpid.AMQException;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.framing.BasicContentHeaderProperties;
+import org.apache.qpid.framing.ContentHeaderBody;
+
+public class MessageFactoryRegistry
+{
+ private final Map<String, MessageFactory> _mimeStringToFactoryMap = new HashMap<String, MessageFactory>();
+ private final Map<AMQShortString, MessageFactory> _mimeShortStringToFactoryMap =
+ new HashMap<AMQShortString, MessageFactory>();
+
+ /**
+ * Construct a new registry with the default message factories registered
+ * @return a message factory registry
+ */
+ public static MessageFactoryRegistry newDefaultRegistry()
+ {
+ MessageFactoryRegistry mf = new MessageFactoryRegistry();
+ mf.registerFactory(JMSMapMessage.MIME_TYPE, new JMSMapMessageFactory());
+ mf.registerFactory("text/plain", new JMSTextMessageFactory());
+ mf.registerFactory("text/xml", new JMSTextMessageFactory());
+ 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());
+
+ return mf;
+ }
+
+ public void registerFactory(String mimeType, MessageFactory mf)
+ {
+ if (mf == null)
+ {
+ throw new IllegalArgumentException("Message factory must not be null");
+ }
+
+ _mimeStringToFactoryMap.put(mimeType, mf);
+ _mimeShortStringToFactoryMap.put(new AMQShortString(mimeType), mf);
+ }
+
+ public MessageFactory deregisterFactory(String mimeType)
+ {
+ _mimeShortStringToFactoryMap.remove(new AMQShortString(mimeType));
+
+ return _mimeStringToFactoryMap.remove(mimeType);
+ }
+
+ /**
+ * Create a message. This looks up the MIME type from the content header and instantiates the appropriate
+ * concrete message type.
+ * @param deliveryTag the AMQ message id
+ * @param redelivered true if redelivered
+ * @param contentHeader the content header that was received
+ * @param bodies a list of ContentBody instances
+ * @return the message.
+ * @throws AMQException
+ * @throws JMSException
+ */
+ public AbstractJMSMessage createMessage(long deliveryTag, boolean redelivered, AMQShortString exchange,
+ AMQShortString routingKey, ContentHeaderBody contentHeader, List bodies)
+ throws AMQException, JMSException
+ {
+ BasicContentHeaderProperties properties = (BasicContentHeaderProperties) contentHeader.properties;
+
+ // Get the message content type. This may be null for pure AMQP messages, but will always be set for JMS over
+ // AMQP. When the type is null, it can only be assumed that the message is a byte message.
+ AMQShortString contentTypeShortString = properties.getContentType();
+ contentTypeShortString = (contentTypeShortString == null) ? new AMQShortString(JMSBytesMessage.MIME_TYPE)
+ : contentTypeShortString;
+
+ MessageFactory mf = _mimeShortStringToFactoryMap.get(contentTypeShortString);
+ if (mf == null)
+ {
+ throw new AMQException("Unsupport MIME type of " + properties.getContentTypeAsString());
+ }
+ else
+ {
+ return mf.createMessage(deliveryTag, redelivered, contentHeader, exchange, routingKey, bodies);
+ }
+ }
+
+ public AbstractJMSMessage createMessage(String mimeType) throws AMQException, JMSException
+ {
+ if (mimeType == null)
+ {
+ throw new IllegalArgumentException("Mime type must not be null");
+ }
+
+ MessageFactory mf = _mimeStringToFactoryMap.get(mimeType);
+ if (mf == null)
+ {
+ throw new AMQException("Unsupport MIME type of " + mimeType);
+ }
+ else
+ {
+ return mf.createMessage();
+ }
+ }
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/client/message/UnexpectedBodyReceivedException.java b/Final/java/client/src/main/java/org/apache/qpid/client/message/UnexpectedBodyReceivedException.java
new file mode 100644
index 0000000000..1f61a661d4
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/message/UnexpectedBodyReceivedException.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.client.message;
+
+import org.apache.qpid.AMQException;
+import org.apache.qpid.protocol.AMQConstant;
+
+/**
+ * @todo Not used! Delete!
+ */
+public class UnexpectedBodyReceivedException extends AMQException
+{
+ public UnexpectedBodyReceivedException(String msg, Throwable t)
+ {
+ super(msg, t);
+ }
+
+ public UnexpectedBodyReceivedException(String msg)
+ {
+ super(msg);
+ }
+
+ public UnexpectedBodyReceivedException(AMQConstant errorCode, String msg)
+ {
+ super(errorCode, msg);
+ }
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/client/message/UnprocessedMessage.java b/Final/java/client/src/main/java/org/apache/qpid/client/message/UnprocessedMessage.java
new file mode 100644
index 0000000000..5b199f2478
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/message/UnprocessedMessage.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.client.message;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.qpid.framing.BasicDeliverBody;
+import org.apache.qpid.framing.BasicReturnBody;
+import org.apache.qpid.framing.ContentBody;
+import org.apache.qpid.framing.ContentHeaderBody;
+
+/**
+ * This class contains everything needed to process a JMS message. It assembles the deliver body, the content header and
+ * the content body/ies.
+ *
+ * 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 class UnprocessedMessage
+{
+ private long _bytesReceived = 0;
+
+ private final BasicDeliverBody _deliverBody;
+ private final BasicReturnBody _bounceBody; // TODO: check change (gustavo)
+ private final int _channelId;
+ private ContentHeaderBody _contentHeader;
+
+ /** List of ContentBody instances. Due to fragmentation you don't know how big this will be in general */
+ private List<ContentBody> _bodies;
+
+ public UnprocessedMessage(int channelId, BasicDeliverBody deliverBody)
+ {
+ _deliverBody = deliverBody;
+ _channelId = channelId;
+ _bounceBody = null;
+ }
+
+
+ public UnprocessedMessage(int channelId, BasicReturnBody bounceBody)
+ {
+ _deliverBody = null;
+ _channelId = channelId;
+ _bounceBody = bounceBody;
+ }
+
+ public void receiveBody(ContentBody body) //throws UnexpectedBodyReceivedException
+ {
+
+ if (body.payload != null)
+ {
+ final long payloadSize = body.payload.remaining();
+
+ if (_bodies == null)
+ {
+ if (payloadSize == getContentHeader().bodySize)
+ {
+ _bodies = Collections.singletonList(body);
+ }
+ else
+ {
+ _bodies = new ArrayList<ContentBody>();
+ _bodies.add(body);
+ }
+
+ }
+ else
+ {
+ _bodies.add(body);
+ }
+ _bytesReceived += payloadSize;
+ }
+ }
+
+ public boolean isAllBodyDataReceived()
+ {
+ return _bytesReceived == getContentHeader().bodySize;
+ }
+
+ public BasicDeliverBody getDeliverBody()
+ {
+ return _deliverBody;
+ }
+
+ public BasicReturnBody getBounceBody()
+ {
+ return _bounceBody;
+ }
+
+
+ public int getChannelId()
+ {
+ return _channelId;
+ }
+
+
+ public ContentHeaderBody getContentHeader()
+ {
+ return _contentHeader;
+ }
+
+ public void setContentHeader(ContentHeaderBody contentHeader)
+ {
+ this._contentHeader = contentHeader;
+ }
+
+ public List<ContentBody> getBodies()
+ {
+ return _bodies;
+ }
+
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/client/protocol/AMQProtocolHandler.java b/Final/java/client/src/main/java/org/apache/qpid/client/protocol/AMQProtocolHandler.java
new file mode 100644
index 0000000000..e7ff5afceb
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/protocol/AMQProtocolHandler.java
@@ -0,0 +1,732 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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.IdleStatus;
+import org.apache.mina.common.IoHandlerAdapter;
+import org.apache.mina.common.IoSession;
+import org.apache.mina.filter.SSLFilter;
+import org.apache.mina.filter.codec.ProtocolCodecException;
+import org.apache.mina.filter.codec.ProtocolCodecFilter;
+
+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.failover.FailoverException;
+import org.apache.qpid.client.failover.FailoverHandler;
+import org.apache.qpid.client.failover.FailoverState;
+import org.apache.qpid.client.state.AMQState;
+import org.apache.qpid.client.state.AMQStateManager;
+import org.apache.qpid.client.state.listener.SpecificMethodFrameListener;
+import org.apache.qpid.codec.AMQCodecFactory;
+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.ContentBody;
+import org.apache.qpid.framing.ContentHeaderBody;
+import org.apache.qpid.framing.HeartbeatBody;
+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.ssl.SSLContextFactory;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Iterator;
+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
+ * specific event model of AMQP, by revealing the type of the received events (from decoded data), and passing the
+ * event on to more specific handlers for the type. In this sense, it channels the richer event model of AMQP,
+ * expressed in terms of methods and so on, through the cruder, general purpose event model of MINA, expressed in
+ * terms of "message received" and so on.
+ *
+ * <p/>There is a 1:1 mapping between an AMQProtocolHandler and an {@link AMQConnection}. The connection class is
+ * exposed to the end user of the AMQP client API, and also implements the JMS Connection API, so provides the public
+ * API calls through which an individual connection can be manipulated. This protocol handler talks to the network
+ * through MINA, in a behind the scenes role; it is not an exposed part of the client API.
+ *
+ * <p/>There is a 1:many mapping between an AMQProtocolHandler and a set of {@link AMQSession}s. At the MINA level,
+ * there is one session per connection. At the AMQP level there can be many channels which are also called sessions in
+ * JMS parlance. The {@link AMQSession}s are managed through an {@link AMQProtocolSession} instance. The protocol
+ * session is similar to the MINA per-connection session, except that it can span the lifecycle of multiple MINA sessions
+ * in the event of failover. See below for more information about this.
+ *
+ * <p/>Mina provides a session container that can be used to store/retrieve arbitrary objects as String named
+ * attributes. A more convenient, type-safe, container for session data is provided in the form of
+ * {@link AMQProtocolSession}.
+ *
+ * <p/>A common way to use MINA is to have a single instance of the event handler, and for MINA to pass in its session
+ * object with every event, and for per-connection data to be held in the MINA session (perhaps using a type-safe wrapper
+ * as described above). This event handler is different, because dealing with failover complicates things. To the
+ * end client of an AMQConnection, a failed over connection is still handled through the same connection instance, but
+ * behind the scenes a new transport connection, and MINA session will have been created. The MINA session object cannot
+ * be used to track the state of the fail-over process, because it is destroyed and a new one is created, as the old
+ * connection is shutdown and a new one created. For this reason, an AMQProtocolHandler is created per AMQConnection
+ * and the protocol session data is held outside of the MINA IOSession.
+ *
+ * <p/>This handler is responsibile for setting up the filter chain to filter all events for this handler through.
+ * The filter chain is set up as a stack of event handers that perform the following functions (working upwards from
+ * the network traffic at the bottom), handing off incoming events to an asynchronous thread pool to do the work,
+ * optionally handling secure sockets encoding/decoding, encoding/decoding the AMQP format itself.
+ *
+ * <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
+ * be merged, although there is sense in keeping the session model seperate. Will clarify things by having data
+ * 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
+{
+ /** Used for debugging. */
+ private static final Logger _logger = LoggerFactory.getLogger(AMQProtocolHandler.class);
+
+ /**
+ * The connection that this protocol handler is associated with. There is a 1-1 mapping between connection
+ * instances and protocol handler instances.
+ */
+ private AMQConnection _connection;
+
+ /** Our wrapper for a protocol session that provides access to session values in a typesafe manner. */
+ private volatile AMQProtocolSession _protocolSession;
+
+ /** Holds the state of the protocol session. */
+ private AMQStateManager _stateManager = new AMQStateManager();
+
+ /** Holds the method listeners, */
+ private final CopyOnWriteArraySet _frameListeners = new CopyOnWriteArraySet();
+
+ /**
+ * We create the failover handler when the session is created since it needs a reference to the IoSession in order
+ * to be able to send errors during failover back to the client application. The session won't be available in the
+ * case where we failing over due to a Connection.Redirect message from the broker.
+ */
+ private FailoverHandler _failoverHandler;
+
+ /**
+ * This flag is used to track whether failover is being attempted. It is used to prevent the application constantly
+ * attempting failover where it is failing.
+ */
+ private FailoverState _failoverState = FailoverState.NOT_STARTED;
+
+ /** Used to provide a condition to wait upon for operations that are required to wait for failover to complete. */
+ private CountDownLatch _failoverLatch;
+
+ /** Defines the default timeout to use for synchronous protocol commands. */
+ private final long DEFAULT_SYNC_TIMEOUT = 1000 * 30;
+
+ /**
+ * Creates a new protocol handler, associated with the specified client connection instance.
+ *
+ * @param con The client connection that this is the event handler for.
+ */
+ 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)
+ {
+ e.printStackTrace();
+ }
+
+ _protocolSession = new AMQProtocolSession(this, session, _connection, getStateManager());
+ _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
+ * where the connection died, an attempt to failover automatically to a new connection may be started. The failover
+ * 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)
+ {
+ if (_connection.isClosed())
+ {
+ _logger.debug("Session closed called by client");
+ }
+ else
+ {
+ _logger.debug("Session closed called with failover state currently " + _failoverState);
+
+ // reconnetablility was introduced here so as not to disturb the client as they have made their intentions
+ // known through the policy settings.
+
+ if ((_failoverState != FailoverState.IN_PROGRESS) && _connection.failoverAllowed())
+ {
+ _logger.debug("FAILOVER STARTING");
+ if (_failoverState == FailoverState.NOT_STARTED)
+ {
+ _failoverState = FailoverState.IN_PROGRESS;
+ startFailoverThread();
+ }
+ else
+ {
+ _logger.debug("Not starting failover as state currently " + _failoverState);
+ }
+ }
+ else
+ {
+ _logger.debug("Failover not allowed by policy."); // or already in progress?
+
+ if (_logger.isDebugEnabled())
+ {
+ _logger.debug(_connection.getFailoverPolicy().toString());
+ }
+
+ if (_failoverState != FailoverState.IN_PROGRESS)
+ {
+ _logger.debug("sessionClose() not allowed to failover");
+ _connection.exceptionReceived(new AMQDisconnectedException(
+ "Server closed connection and reconnection " + "not permitted."));
+ }
+ else
+ {
+ _logger.debug("sessionClose() failover in progress");
+ }
+ }
+ }
+
+ _logger.debug("Protocol Session [" + this + "] closed");
+ }
+
+ /** 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();
+ }
+
+ public void sessionIdle(IoSession session, IdleStatus status) throws Exception
+ {
+ _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();
+ }
+ }
+
+ /**
+ * 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.
+ */
+ public void exceptionCaught(IoSession session, Throwable cause)
+ {
+ if (_failoverState == FailoverState.NOT_STARTED)
+ {
+ // if (!(cause instanceof AMQUndeliveredException) && (!(cause instanceof AMQAuthenticationException)))
+ if (cause instanceof AMQConnectionClosedException)
+ {
+ _logger.info("Exception caught therefore going to attempt failover: " + cause, cause);
+ // this will attemp failover
+
+ sessionClosed(session);
+ }
+ else
+ {
+
+ if (cause instanceof ProtocolCodecException)
+ {
+ _logger.info("Protocol Exception caught NOT going to attempt failover as " +
+ "cause isn't AMQConnectionClosedException: " + cause, cause);
+
+ AMQException amqe = new AMQException("Protocol handler error: " + cause, cause);
+ propagateExceptionToWaiters(amqe);
+ _connection.exceptionReceived(cause);
+ }
+
+ }
+
+ // FIXME Need to correctly handle other exceptions. Things like ...
+ // if (cause instanceof AMQChannelClosedException)
+ // which will cause the JMSSession to end due to a channel close and so that Session needs
+ // to be removed from the map so we can correctly still call close without an exception when trying to close
+ // the server closed session. See also CloseChannelMethodHandler as the sessionClose is never called on exception
+ }
+ // we reach this point if failover was attempted and failed therefore we need to let the calling app
+ // know since we cannot recover the situation
+ else if (_failoverState == FailoverState.FAILED)
+ {
+ _logger.error("Exception caught by protocol handler: " + cause, cause);
+
+ // we notify the state manager of the error in case we have any clients waiting on a state
+ // change. Those "waiters" will be interrupted and can handle the exception
+ AMQException amqe = new AMQException("Protocol handler error: " + cause, cause);
+ propagateExceptionToWaiters(amqe);
+ _connection.exceptionReceived(cause);
+ }
+ }
+
+ /**
+ * There are two cases where we have other threads potentially blocking for events to be handled by this class.
+ * These are for the state manager (waiting for a state change) or a frame listener (waiting for a particular type
+ * of frame to arrive). When an error occurs we need to notify these waiters so that they can react appropriately.
+ *
+ * @param e the exception to propagate
+ */
+ public void propagateExceptionToWaiters(Exception e)
+ {
+ getStateManager().error(e);
+ if (!_frameListeners.isEmpty())
+ {
+ final Iterator it = _frameListeners.iterator();
+ while (it.hasNext())
+ {
+ final AMQMethodListener ml = (AMQMethodListener) it.next();
+ ml.error(e);
+ }
+ }
+ }
+
+ private static int _messageReceivedCount;
+
+ public void messageReceived(IoSession session, Object message) throws Exception
+ {
+ 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);
+
+ switch (bodyFrame.getFrameType())
+ {
+ case AMQMethodBody.TYPE:
+
+ if (debug)
+ {
+ _logger.debug("(" + System.identityHashCode(this) + ")Method frame received: " + frame);
+ }
+
+ final AMQMethodEvent<AMQMethodBody> evt =
+ new AMQMethodEvent<AMQMethodBody>(frame.getChannel(), (AMQMethodBody) bodyFrame);
+
+ try
+ {
+
+ boolean wasAnyoneInterested = getStateManager().methodReceived(evt);
+ if (!_frameListeners.isEmpty())
+ {
+ Iterator it = _frameListeners.iterator();
+ while (it.hasNext())
+ {
+ final AMQMethodListener listener = (AMQMethodListener) it.next();
+ wasAnyoneInterested = listener.methodReceived(evt) || wasAnyoneInterested;
+ }
+ }
+
+ if (!wasAnyoneInterested)
+ {
+ throw new AMQException("AMQMethodEvent " + evt + " was not processed by any listener. Listeners:"
+ + _frameListeners);
+ }
+ }
+ catch (AMQException e)
+ {
+ getStateManager().error(e);
+ if (!_frameListeners.isEmpty())
+ {
+ Iterator it = _frameListeners.iterator();
+ while (it.hasNext())
+ {
+ final AMQMethodListener listener = (AMQMethodListener) it.next();
+ listener.error(e);
+ }
+ }
+
+ exceptionCaught(session, e);
+ }
+
+ break;
+
+ case ContentHeaderBody.TYPE:
+
+ _protocolSession.messageContentHeaderReceived(frame.getChannel(), (ContentHeaderBody) bodyFrame);
+ break;
+
+ case ContentBody.TYPE:
+
+ _protocolSession.messageContentBodyReceived(frame.getChannel(), (ContentBody) bodyFrame);
+ break;
+
+ case HeartbeatBody.TYPE:
+
+ if (debug)
+ {
+ _logger.debug("Received heartbeat");
+ }
+
+ break;
+
+ default:
+
+ }
+
+ _connection.bytesReceived(_protocolSession.getIoSession().getReadBytes());
+ }
+
+ private static int _messagesOut;
+
+ public void messageSent(IoSession session, Object message) throws Exception
+ {
+ final long sentMessages = _messagesOut++;
+
+ final boolean debug = _logger.isDebugEnabled();
+
+ if (debug && ((sentMessages % 1000) == 0))
+ {
+ _logger.debug("Sent " + _messagesOut + " protocol messages");
+ }
+
+ _connection.bytesSent(session.getWrittenBytes());
+ if (debug)
+ {
+ _logger.debug("Sent frame " + message);
+ }
+ }
+
+ /*
+ public void addFrameListener(AMQMethodListener listener)
+ {
+ _frameListeners.add(listener);
+ }
+
+ public void removeFrameListener(AMQMethodListener listener)
+ {
+ _frameListeners.remove(listener);
+ }
+ */
+ public void attainState(AMQState s) throws AMQException
+ {
+ getStateManager().attainState(s);
+ }
+
+ /**
+ * 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)
+ {
+ _protocolSession.writeFrame(frame);
+ }
+
+ public void writeFrame(AMQDataBlock frame, boolean wait)
+ {
+ _protocolSession.writeFrame(frame, wait);
+ }
+
+ /**
+ * Convenience method that writes a frame to the protocol session and waits for a particular response. Equivalent to
+ * calling getProtocolSession().write() then waiting for the response.
+ *
+ * @param frame
+ * @param listener the blocking listener. Note the calling thread will block.
+ */
+ public AMQMethodEvent writeCommandFrameAndWaitForReply(AMQFrame frame, BlockingMethodFrameListener listener)
+ throws AMQException, FailoverException
+ {
+ return writeCommandFrameAndWaitForReply(frame, listener, DEFAULT_SYNC_TIMEOUT);
+ }
+
+ /**
+ * Convenience method that writes a frame to the protocol session and waits for a particular response. Equivalent to
+ * calling getProtocolSession().write() then waiting for the response.
+ *
+ * @param frame
+ * @param listener the blocking listener. Note the calling thread will block.
+ */
+ public AMQMethodEvent writeCommandFrameAndWaitForReply(AMQFrame frame, BlockingMethodFrameListener listener,
+ long timeout) throws AMQException, FailoverException
+ {
+ try
+ {
+ _frameListeners.add(listener);
+ _protocolSession.writeFrame(frame);
+
+ AMQMethodEvent e = listener.blockForFrame(timeout);
+
+ return e;
+ // When control resumes before this line, a reply will have been received
+ // that matches the criteria defined in the blocking listener
+ }
+ catch (AMQException e)
+ {
+ throw e;
+ }
+ finally
+ {
+ // If we don't removeKey the listener then no-one will
+ _frameListeners.remove(listener);
+ }
+
+ }
+
+ /** More convenient method to write a frame and wait for it's response. */
+ public AMQMethodEvent syncWrite(AMQFrame frame, Class responseClass) throws AMQException, FailoverException
+ {
+ return syncWrite(frame, responseClass, DEFAULT_SYNC_TIMEOUT);
+ }
+
+ /** More convenient method to write a frame and wait for it's response. */
+ public AMQMethodEvent syncWrite(AMQFrame frame, Class responseClass, long timeout) throws AMQException, FailoverException
+ {
+ return writeCommandFrameAndWaitForReply(frame, new SpecificMethodFrameListener(frame.getChannel(), responseClass),
+ timeout);
+ }
+
+ public void closeSession(AMQSession session) throws AMQException
+ {
+ _protocolSession.closeSession(session);
+ }
+
+ /**
+ * Closes the connection.
+ *
+ * <p/>If a failover exception occurs whilst closing the connection it is ignored, as the connection is closed
+ * anyway.
+ *
+ * @param timeout The timeout to wait for an acknowledgement to the close request.
+ *
+ * @throws AMQException If the close fails for any reason.
+ */
+ public void closeConnection(long timeout) throws AMQException
+ {
+ getStateManager().changeState(AMQState.CONNECTION_CLOSING);
+
+ // AMQP version change: Hardwire the version to 0-8 (major=8, minor=0)
+ // TODO: Connect this to the session version obtained from ProtocolInitiation for this session.
+ // Be aware of possible changes to parameter order as versions change.
+ final AMQFrame frame =
+ ConnectionCloseBody.createAMQFrame(0, _protocolSession.getProtocolMajorVersion(),
+ _protocolSession.getProtocolMinorVersion(), // AMQP version (major, minor)
+ 0, // classId
+ 0, // methodId
+ AMQConstant.REPLY_SUCCESS.getCode(), // replyCode
+ new AMQShortString("JMS client is closing the connection.")); // replyText
+
+ try
+ {
+ syncWrite(frame, ConnectionCloseOkBody.class, timeout);
+ _protocolSession.closeProtocolSession();
+ }
+ catch (AMQTimeoutException e)
+ {
+ _protocolSession.closeProtocolSession(false);
+ }
+ catch (FailoverException e)
+ {
+ _logger.debug("FailoverException interrupted connection close, ignoring as connection close anyway.");
+ }
+ }
+
+ /** @return the number of bytes read from this protocol session */
+ public long getReadBytes()
+ {
+ return _protocolSession.getIoSession().getReadBytes();
+ }
+
+ /** @return the number of bytes written to this protocol session */
+ public long getWrittenBytes()
+ {
+ return _protocolSession.getIoSession().getWrittenBytes();
+ }
+
+ public void failover(String host, int port)
+ {
+ _failoverHandler.setHost(host);
+ _failoverHandler.setPort(port);
+ // see javadoc for FailoverHandler to see rationale for separate thread
+ startFailoverThread();
+ }
+
+ public void blockUntilNotFailingOver() throws InterruptedException
+ {
+ if (_failoverLatch != null)
+ {
+ _failoverLatch.await();
+ }
+ }
+
+ public AMQShortString generateQueueName()
+ {
+ return _protocolSession.generateQueueName();
+ }
+
+ public CountDownLatch getFailoverLatch()
+ {
+ return _failoverLatch;
+ }
+
+ public void setFailoverLatch(CountDownLatch failoverLatch)
+ {
+ _failoverLatch = failoverLatch;
+ }
+
+ public AMQConnection getConnection()
+ {
+ return _connection;
+ }
+
+ public AMQStateManager getStateManager()
+ {
+ return _stateManager;
+ }
+
+ public void setStateManager(AMQStateManager stateManager)
+ {
+ _stateManager = stateManager;
+ if (_protocolSession != null)
+ {
+ _protocolSession.setStateManager(stateManager);
+ }
+ }
+
+ public AMQProtocolSession getProtocolSession()
+ {
+ return _protocolSession;
+ }
+
+ FailoverState getFailoverState()
+ {
+ return _failoverState;
+ }
+
+ public void setFailoverState(FailoverState failoverState)
+ {
+ _failoverState = failoverState;
+ }
+
+ public byte getProtocolMajorVersion()
+ {
+ return _protocolSession.getProtocolMajorVersion();
+ }
+
+ public byte getProtocolMinorVersion()
+ {
+ return _protocolSession.getProtocolMinorVersion();
+ }
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/client/protocol/AMQProtocolSession.java b/Final/java/client/src/main/java/org/apache/qpid/client/protocol/AMQProtocolSession.java
new file mode 100644
index 0000000000..5fe6ffe6c6
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/protocol/AMQProtocolSession.java
@@ -0,0 +1,459 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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.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.apache.qpid.AMQException;
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.client.AMQSession;
+import org.apache.qpid.client.ConnectionTuneParameters;
+// import org.apache.qpid.client.message.UnexpectedBodyReceivedException;
+import org.apache.qpid.client.message.UnprocessedMessage;
+import org.apache.qpid.client.state.AMQStateManager;
+import org.apache.qpid.framing.AMQDataBlock;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.framing.ContentBody;
+import org.apache.qpid.framing.ContentHeaderBody;
+import org.apache.qpid.framing.MainRegistry;
+import org.apache.qpid.framing.ProtocolInitiation;
+import org.apache.qpid.framing.ProtocolVersion;
+import org.apache.qpid.framing.VersionSpecificRegistry;
+import org.apache.qpid.protocol.AMQConstant;
+import org.apache.qpid.protocol.AMQVersionAwareProtocolSession;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.jms.JMSException;
+import javax.security.sasl.SaslClient;
+
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.UUID;
+
+/**
+ * Wrapper for protocol session that provides type-safe access to session attributes. <p/> The underlying protocol
+ * session is still available but clients should not use it to obtain session attributes.
+ */
+public class AMQProtocolSession implements AMQVersionAwareProtocolSession
+{
+ protected static final int LAST_WRITE_FUTURE_JOIN_TIMEOUT = 1000 * 60 * 2;
+
+ protected static final Logger _logger = LoggerFactory.getLogger(AMQProtocolSession.class);
+
+ public static final String PROTOCOL_INITIATION_RECEIVED = "ProtocolInitiatiionReceived";
+
+ protected static final String CONNECTION_TUNE_PARAMETERS = "ConnectionTuneParameters";
+
+ protected static final String AMQ_CONNECTION = "AMQConnection";
+
+ protected static final String SASL_CLIENT = "SASLClient";
+
+ protected final IoSession _minaProtocolSession;
+
+ private AMQStateManager _stateManager;
+
+ 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.
+ */
+ protected final AMQProtocolHandler _protocolHandler;
+
+ /** Maps from the channel id to the AMQSession that it represents. */
+ protected ConcurrentMap<Integer, AMQSession> _channelId2SessionMap = new ConcurrentHashMap<Integer, AMQSession>();
+
+ protected ConcurrentMap _closingChannels = new ConcurrentHashMap();
+
+ /**
+ * Maps from a channel id to an unprocessed message. This is used to tie together the JmsDeliverBody (which arrives
+ * first) with the subsequent content header and content bodies.
+ */
+ protected ConcurrentMap _channelId2UnprocessedMsgMap = new ConcurrentHashMap();
+
+ /** Counter to ensure unique queue names */
+ protected int _queueId = 1;
+ protected final Object _queueIdLock = new Object();
+
+ private byte _protocolMinorVersion;
+ private byte _protocolMajorVersion;
+ private VersionSpecificRegistry _registry =
+ MainRegistry.getVersionSpecificRegistry(ProtocolVersion.getLatestSupportedVersion());
+
+ private final AMQConnection _connection;
+
+ public AMQProtocolSession(AMQProtocolHandler protocolHandler, IoSession protocolSession, AMQConnection connection)
+ {
+ this(protocolHandler, protocolSession, connection, new AMQStateManager());
+
+ }
+
+ public AMQProtocolSession(AMQProtocolHandler protocolHandler, IoSession protocolSession, AMQConnection connection,
+ AMQStateManager stateManager)
+ {
+ _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);
+ _stateManager = stateManager;
+ _stateManager.setProtocolSession(this);
+ _connection = connection;
+
+ }
+
+ public void init()
+ {
+ // start the process of setting up the connection. This is the first place that
+ // data is written to the server.
+
+ _minaProtocolSession.write(new ProtocolInitiation(ProtocolVersion.getLatestSupportedVersion()));
+ }
+
+ public String getClientID()
+ {
+ try
+ {
+ return getAMQConnection().getClientID();
+ }
+ catch (JMSException e)
+ {
+ // we never throw a JMSException here
+ return null;
+ }
+ }
+
+ public void setClientID(String clientID) throws JMSException
+ {
+ getAMQConnection().setClientID(clientID);
+ }
+
+ public AMQStateManager getStateManager()
+ {
+ return _stateManager;
+ }
+
+ public void setStateManager(AMQStateManager stateManager)
+ {
+ _stateManager = stateManager;
+ }
+
+ public String getVirtualHost()
+ {
+ return getAMQConnection().getVirtualHost();
+ }
+
+ public String getUsername()
+ {
+ return getAMQConnection().getUsername();
+ }
+
+ public String getPassword()
+ {
+ return getAMQConnection().getPassword();
+ }
+
+ public IoSession getIoSession()
+ {
+ return _minaProtocolSession;
+ }
+
+ public SaslClient getSaslClient()
+ {
+ return (SaslClient) _minaProtocolSession.getAttribute(SASL_CLIENT);
+ }
+
+ /**
+ * Store the SASL client currently being used for the authentication handshake
+ *
+ * @param client if non-null, stores this in the session. if null clears any existing client being stored
+ */
+ public void setSaslClient(SaslClient client)
+ {
+ if (client == null)
+ {
+ _minaProtocolSession.removeAttribute(SASL_CLIENT);
+ }
+ else
+ {
+ _minaProtocolSession.setAttribute(SASL_CLIENT, client);
+ }
+ }
+
+ public ConnectionTuneParameters getConnectionTuneParameters()
+ {
+ return (ConnectionTuneParameters) _minaProtocolSession.getAttribute(CONNECTION_TUNE_PARAMETERS);
+ }
+
+ public void setConnectionTuneParameters(ConnectionTuneParameters params)
+ {
+ _minaProtocolSession.setAttribute(CONNECTION_TUNE_PARAMETERS, params);
+ AMQConnection con = getAMQConnection();
+ con.setMaximumChannelCount(params.getChannelMax());
+ con.setMaximumFrameSize(params.getFrameMax());
+ initHeartbeats((int) params.getHeartbeat());
+ }
+
+ /**
+ * Callback invoked from the BasicDeliverMethodHandler when a message has been received. This is invoked on the MINA
+ * dispatcher thread.
+ *
+ * @param message
+ *
+ * @throws AMQException if this was not expected
+ */
+ public void unprocessedMessageReceived(UnprocessedMessage message) throws AMQException
+ {
+ _channelId2UnprocessedMsgMap.put(message.getChannelId(), message);
+ }
+
+ public void messageContentHeaderReceived(int channelId, ContentHeaderBody contentHeader) throws AMQException
+ {
+ UnprocessedMessage msg = (UnprocessedMessage) _channelId2UnprocessedMsgMap.get(channelId);
+ if (msg == null)
+ {
+ throw new AMQException("Error: received content header without having received a BasicDeliver frame first");
+ }
+
+ if (msg.getContentHeader() != null)
+ {
+ throw new AMQException(
+ "Error: received duplicate content header or did not receive correct number of content body frames");
+ }
+
+ msg.setContentHeader(contentHeader);
+ if (contentHeader.bodySize == 0)
+ {
+ deliverMessageToAMQSession(channelId, msg);
+ }
+ }
+
+ public void messageContentBodyReceived(int channelId, ContentBody contentBody) throws AMQException
+ {
+ UnprocessedMessage msg = (UnprocessedMessage) _channelId2UnprocessedMsgMap.get(channelId);
+ if (msg == null)
+ {
+ throw new AMQException("Error: received content body without having received a JMSDeliver frame first");
+ }
+
+ if (msg.getContentHeader() == null)
+ {
+ _channelId2UnprocessedMsgMap.remove(channelId);
+ throw new AMQException("Error: received content body without having received a ContentHeader frame first");
+ }
+
+ /*try
+ {*/
+ msg.receiveBody(contentBody);
+ /*}
+ catch (UnexpectedBodyReceivedException e)
+ {
+ _channelId2UnprocessedMsgMap.remove(channelId);
+ throw e;
+ }*/
+
+ if (msg.isAllBodyDataReceived())
+ {
+ deliverMessageToAMQSession(channelId, msg);
+ }
+ }
+
+ /**
+ * Deliver a message to the appropriate session, removing the unprocessed message from our map
+ *
+ * @param channelId the channel id the message should be delivered to
+ * @param msg the message
+ */
+ private void deliverMessageToAMQSession(int channelId, UnprocessedMessage msg)
+ {
+ AMQSession session = getSession(channelId);
+ session.messageReceived(msg);
+ _channelId2UnprocessedMsgMap.remove(channelId);
+ }
+
+ protected AMQSession getSession(int channelId)
+ {
+ return _connection.getSession(channelId);
+ }
+
+ /**
+ * 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)
+ {
+ writeFrame(frame, false);
+ }
+
+ public void writeFrame(AMQDataBlock frame, boolean wait)
+ {
+ WriteFuture f = _minaProtocolSession.write(frame);
+ if (wait)
+ {
+ // fixme -- time out?
+ f.join();
+ }
+ else
+ {
+ _lastWriteFuture = f;
+ }
+ }
+
+ /**
+ * Starts the process of closing a session
+ *
+ * @param session the AMQSession being closed
+ */
+ public void closeSession(AMQSession session)
+ {
+ _logger.debug("closeSession called on protocol session for session " + session.getChannelId());
+ final int channelId = session.getChannelId();
+ if (channelId <= 0)
+ {
+ throw new IllegalArgumentException("Attempt to close a channel with id < 0");
+ }
+ // we need to know when a channel is closing so that we can respond
+ // with a channel.close frame when we receive any other type of frame
+ // on that channel
+ _closingChannels.putIfAbsent(channelId, session);
+ }
+
+ /**
+ * Called from the ChannelClose handler when a channel close frame is received. This method decides whether this is
+ * a response or an initiation. The latter case causes the AMQSession to be closed and an exception to be thrown if
+ * appropriate.
+ *
+ * @param channelId the id of the channel (session)
+ *
+ * @return true if the client must respond to the server, i.e. if the server initiated the channel close, false if
+ * the channel close is just the server responding to the client's earlier request to close the channel.
+ */
+ public boolean channelClosed(int channelId, AMQConstant code, String text) throws AMQException
+ {
+
+ // if this is not a response to an earlier request to close the channel
+ if (_closingChannels.remove(channelId) == null)
+ {
+ final AMQSession session = getSession(channelId);
+ try
+ {
+ session.closed(new AMQException(code, text));
+ }
+ catch (JMSException e)
+ {
+ throw new AMQException("JMSException received while closing session", e);
+ }
+
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ public AMQConnection getAMQConnection()
+ {
+ return (AMQConnection) _minaProtocolSession.getAttribute(AMQ_CONNECTION);
+ }
+
+ 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("Closing protocol session");
+ final CloseFuture future = _minaProtocolSession.close();
+ future.join(LAST_WRITE_FUTURE_JOIN_TIMEOUT);
+ }
+
+ public void failover(String host, int port)
+ {
+ _protocolHandler.failover(host, port);
+ }
+
+ protected AMQShortString generateQueueName()
+ {
+ int id;
+
+ return new AMQShortString("tmp_" + UUID.randomUUID());
+ }
+
+ /** @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);
+
+ session.confirmConsumerCancelled(consumerTag);
+ }
+
+ public void setProtocolVersion(final byte versionMajor, final byte versionMinor)
+ {
+ _protocolMajorVersion = versionMajor;
+ _protocolMinorVersion = versionMinor;
+ _registry = MainRegistry.getVersionSpecificRegistry(versionMajor, versionMinor);
+ }
+
+ public byte getProtocolMinorVersion()
+ {
+ return _protocolMinorVersion;
+ }
+
+ public byte getProtocolMajorVersion()
+ {
+ return _protocolMajorVersion;
+ }
+
+ public VersionSpecificRegistry getRegistry()
+ {
+ return _registry;
+ }
+
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/client/protocol/BlockingMethodFrameListener.java b/Final/java/client/src/main/java/org/apache/qpid/client/protocol/BlockingMethodFrameListener.java
new file mode 100644
index 0000000000..1badbb601c
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/protocol/BlockingMethodFrameListener.java
@@ -0,0 +1,311 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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 java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.ReentrantLock;
+
+import org.apache.qpid.AMQException;
+import org.apache.qpid.AMQTimeoutException;
+import org.apache.qpid.client.failover.FailoverException;
+import org.apache.qpid.framing.AMQMethodBody;
+import org.apache.qpid.protocol.AMQMethodEvent;
+import org.apache.qpid.protocol.AMQMethodListener;
+
+/**
+ * BlockingMethodFrameListener is a 'rendezvous' which acts as a {@link AMQMethodListener} that delegates handling of
+ * incoming methods to a method listener implemented as a sub-class of this and hands off the processed method or
+ * error to a consumer. The producer of the event does not have to wait for the consumer to take the event, so this
+ * differs from a 'rendezvous' in that sense.
+ *
+ * <p/>BlockingMethodFrameListeners are used to coordinate waiting for replies to method calls that expect a response.
+ * They are always used in a 'one-shot' manner, that is, to recieve just one response. Usually the caller has to register
+ * them as method listeners with an event dispatcher and remember to de-register them (in a finally block) once they
+ * have been completed.
+ *
+ * <p/>The {@link #processMethod} must return <tt>true</tt> on any incoming method that it handles. This indicates to
+ * this listeners that the method it is waiting for has arrived. Incoming methods are also filtered by channel prior to
+ * being passed to the {@link #processMethod} method, so responses are only received for a particular channel. The
+ * channel id must be passed to the constructor.
+ *
+ * <p/>Errors from the producer are rethrown to the consumer.
+ *
+ * <p/><table id="crc"><caption>CRC Card</caption>
+ * <tr><th> Responsibilities <th> Collaborations
+ * <tr><td> Accept notification of AMQP method events. <td> {@link AMQMethodEvent}
+ * <tr><td> Delegate handling of the method to another method listener. <td> {@link AMQMethodBody}
+ * <tr><td> Block until a method is handled by the delegated to handler.
+ * <tr><td> Propagate the most recent exception to the consumer.
+ * </table>
+ *
+ * @todo Might be neater if this method listener simply wrapped another that provided the method handling using a
+ * methodRecevied method. The processMethod takes an additional channelId, however none of the implementations
+ * seem to use it. So wrapping the listeners is possible.
+ *
+ * @todo What is to stop a blocking method listener, receiving a second method whilst it is registered as a listener,
+ * overwriting the first one before the caller of the block method has had a chance to examine it? If one-shot
+ * behaviour is to be intended it should be enforced, perhaps by always returning false once the blocked for
+ * method has been received.
+ *
+ * @todo Interuption is caught but not handled. This could be allowed to fall through. This might actually be usefull
+ * for fail-over where a thread is blocking when failure happens, it could be interrupted to abandon or retry
+ * when this happens. At the very least, restore the interrupted status flag.
+ *
+ * @todo If the retrotranslator can handle it, could use a SynchronousQueue to implement this rendezvous. Need to
+ * check that SynchronousQueue has a non-blocking put method available.
+ */
+public abstract class BlockingMethodFrameListener implements AMQMethodListener
+{
+ /** This flag is used to indicate that the blocked for method has been received. */
+ private volatile boolean _ready = false;
+
+ /** This flag is used to indicate that the received error has been processed. */
+ private volatile boolean _errorAck = false;
+
+ /** Used to protect the shared event and ready flag between the producer and consumer. */
+ private final ReentrantLock _lock = new ReentrantLock();
+
+ /**
+ * Used to signal that a method has been received
+ */
+ private final Condition _receivedCondition = _lock.newCondition();
+
+ /**
+ * Used to signal that a error has been processed
+ */
+ private final Condition _errorConditionAck = _lock.newCondition();
+
+ /** Used to hold the most recent exception that is passed to the {@link #error(Exception)} method. */
+ private volatile Exception _error;
+
+ /** Holds the channel id for the channel upon which this listener is waiting for a response. */
+ protected int _channelId;
+
+ /** Holds the incoming method. */
+ protected AMQMethodEvent _doneEvt = 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 BlockingMethodFrameListener(int channelId)
+ {
+ _channelId = channelId;
+ }
+
+ /**
+ * Delegates any additional handling of the incoming methods to another handler.
+ *
+ * @param channelId The channel id of the incoming method.
+ * @param frame The method body.
+ *
+ * @return <tt>true</tt> if the method was handled, <tt>false</tt> otherwise.
+ */
+ public abstract boolean processMethod(int channelId, AMQMethodBody frame); // throws AMQException;
+
+ /**
+ * Informs this listener that an AMQP method has been received.
+ *
+ * @param evt The AMQP method.
+ *
+ * @return <tt>true</tt> if this listener has handled the method, <tt>false</tt> otherwise.
+ */
+ public boolean methodReceived(AMQMethodEvent evt) // throws AMQException
+ {
+ AMQMethodBody method = evt.getMethod();
+
+ /*try
+ {*/
+ boolean ready = (evt.getChannelId() == _channelId) && processMethod(evt.getChannelId(), method);
+
+ if (ready)
+ {
+ // we only update the flag from inside the synchronized block
+ // so that the blockForFrame method cannot "miss" an update - it
+ // will only ever read the flag from within the synchronized block
+ _lock.lock();
+ try
+ {
+ _doneEvt = evt;
+ _ready = ready;
+ _receivedCondition.signal();
+ }
+ finally
+ {
+ _lock.unlock();
+ }
+ }
+
+ return ready;
+
+ /*}
+ catch (AMQException e)
+ {
+ error(e);
+ // we rethrow the error here, and the code in the frame dispatcher will go round
+ // each listener informing them that an exception has been thrown
+ throw e;
+ }*/
+ }
+
+ /**
+ * Blocks until a method is received that is handled by the delegated to method listener, or the specified timeout
+ * has passed.
+ *
+ * @param timeout The timeout in milliseconds.
+ *
+ * @return The AMQP method that was received.
+ *
+ * @throws AMQException
+ * @throws FailoverException
+ */
+ public AMQMethodEvent blockForFrame(long timeout) throws AMQException, FailoverException
+ {
+ long nanoTimeout = TimeUnit.MILLISECONDS.toNanos(timeout);
+
+ _lock.lock();
+
+ try
+ {
+ while (!_ready)
+ {
+ try
+ {
+ if (timeout == -1)
+ {
+ _receivedCondition.await();
+ }
+ else
+ {
+ nanoTimeout = _receivedCondition.awaitNanos(nanoTimeout);
+
+ if (nanoTimeout <= 0 && !_ready && _error == null)
+ {
+ _error = new AMQTimeoutException("Server did not respond in a timely fashion");
+ _ready = true;
+ }
+ }
+ }
+ catch (InterruptedException e)
+ {
+ // IGNORE -- //fixme this isn't ideal as being interrupted isn't equivellant to sucess
+ // if (!_ready && timeout != -1)
+ // {
+ // _error = new AMQException("Server did not respond timely");
+ // _ready = true;
+ // }
+ }
+ }
+
+
+ if (_error != null)
+ {
+ if (_error instanceof AMQException)
+ {
+ throw (AMQException) _error;
+ }
+ else if (_error instanceof FailoverException)
+ {
+ // This should ensure that FailoverException is not wrapped and can be caught.
+ throw (FailoverException) _error; // needed to expose FailoverException.
+ }
+ else
+ {
+ throw new AMQException("Woken up due to " + _error.getClass(), _error);
+ }
+ }
+
+ }
+ finally
+ {
+ _errorAck = true;
+ _errorConditionAck.signal();
+ _error = null;
+ _lock.unlock();
+ }
+
+ return _doneEvt;
+ }
+
+ /**
+ * This is a callback, called by the MINA dispatcher thread only. It is also called from within this
+ * class to avoid code repetition but again is only called by the MINA dispatcher thread.
+ *
+ * @param e
+ */
+ public void error(Exception e)
+ {
+ // set the error so that the thread that is blocking (against blockForFrame())
+ // can pick up the exception and rethrow to the caller
+
+
+ _lock.lock();
+
+ if (_error == null)
+ {
+ _error = e;
+ }
+ else
+ {
+ System.err.println("WARNING: new error arrived while old one not yet processed");
+ }
+
+ try
+ {
+ _ready = true;
+ _receivedCondition.signal();
+
+ while (!_errorAck)
+ {
+ try
+ {
+ _errorConditionAck.await();
+ }
+ catch (InterruptedException e1)
+ {
+ //
+ }
+ }
+ _errorAck = false;
+ }
+ finally
+ {
+ _lock.unlock();
+ }
+ }
+
+ public boolean equals(Object o)
+ {
+
+ if (o instanceof BlockingMethodFrameListener)
+ {
+ BlockingMethodFrameListener other = (BlockingMethodFrameListener) o;
+
+ return _channelId == other._channelId;
+ }
+
+ return false;
+ }
+
+
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/client/protocol/HeartbeatConfig.java b/Final/java/client/src/main/java/org/apache/qpid/client/protocol/HeartbeatConfig.java
new file mode 100644
index 0000000000..35ea44a331
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/protocol/HeartbeatConfig.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.client.protocol;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+class HeartbeatConfig
+{
+ private static final Logger _logger = LoggerFactory.getLogger(HeartbeatConfig.class);
+ static final HeartbeatConfig CONFIG = new HeartbeatConfig();
+
+ /**
+ * The factor used to get the timeout from the delay between heartbeats.
+ */
+ private float timeoutFactor = 2;
+
+ HeartbeatConfig()
+ {
+ String property = System.getProperty("amqj.heartbeat.timeoutFactor");
+ if (property != null)
+ {
+ try
+ {
+ timeoutFactor = Float.parseFloat(property);
+ }
+ catch (NumberFormatException e)
+ {
+ _logger.warn("Invalid timeout factor (amqj.heartbeat.timeoutFactor): " + property);
+ }
+ }
+ }
+
+ float getTimeoutFactor()
+ {
+ return timeoutFactor;
+ }
+
+ int getTimeout(int writeDelay)
+ {
+ return (int) (timeoutFactor * writeDelay);
+ }
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/client/protocol/HeartbeatDiagnostics.java b/Final/java/client/src/main/java/org/apache/qpid/client/protocol/HeartbeatDiagnostics.java
new file mode 100644
index 0000000000..d44faeab04
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/protocol/HeartbeatDiagnostics.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.client.protocol;
+
+class HeartbeatDiagnostics
+{
+ private static final Diagnostics _impl = init();
+
+ private static Diagnostics init()
+ {
+ return Boolean.getBoolean("amqj.heartbeat.diagnostics") ? new On() : new Off();
+ }
+
+ static void sent()
+ {
+ _impl.sent();
+ }
+
+ static void timeout()
+ {
+ _impl.timeout();
+ }
+
+ static void received(boolean heartbeat)
+ {
+ _impl.received(heartbeat);
+ }
+
+ static void init(int delay, int timeout)
+ {
+ _impl.init(delay, timeout);
+ }
+
+ private static interface Diagnostics
+ {
+ void sent();
+ void timeout();
+ void received(boolean heartbeat);
+ void init(int delay, int timeout);
+ }
+
+ private static class On implements Diagnostics
+ {
+ private final String[] messages = new String[50];
+ private int i;
+
+ private void save(String msg)
+ {
+ messages[i++] = msg;
+ if(i >= messages.length){
+ i = 0;//i.e. a circular buffer
+ }
+ }
+
+ public void sent()
+ {
+ save(System.currentTimeMillis() + ": sent heartbeat");
+ }
+
+ public void timeout()
+ {
+ for(int i = 0; i < messages.length; i++)
+ {
+ if(messages[i] != null)
+ {
+ System.out.println(messages[i]);
+ }
+ }
+ System.out.println(System.currentTimeMillis() + ": timed out");
+ }
+
+ public void received(boolean heartbeat)
+ {
+ save(System.currentTimeMillis() + ": received " + (heartbeat ? "heartbeat" : "data"));
+ }
+
+ public void init(int delay, int timeout)
+ {
+ System.out.println(System.currentTimeMillis() + ": initialised delay=" + delay + ", timeout=" + timeout);
+ }
+ }
+
+ private static class Off implements Diagnostics
+ {
+ public void sent()
+ {
+
+ }
+ public void timeout()
+ {
+
+ }
+ public void received(boolean heartbeat)
+ {
+
+ }
+
+ public void init(int delay, int timeout)
+ {
+
+ }
+ }
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/client/protocol/ProtocolBufferMonitorFilter.java b/Final/java/client/src/main/java/org/apache/qpid/client/protocol/ProtocolBufferMonitorFilter.java
new file mode 100644
index 0000000000..93cc5e7ec3
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/protocol/ProtocolBufferMonitorFilter.java
@@ -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.
+ *
+ */
+package org.apache.qpid.client.protocol;
+
+import org.apache.mina.common.IoFilterAdapter;
+import org.apache.mina.common.IoSession;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A MINA filter that monitors the numbers of messages pending to be sent by MINA. It outputs a message
+ * when a threshold has been exceeded, and has a frequency configuration so that messages are not output
+ * too often.
+ *
+ */
+public class ProtocolBufferMonitorFilter extends IoFilterAdapter
+{
+ private static final Logger _logger = LoggerFactory.getLogger(ProtocolBufferMonitorFilter.class);
+
+ public static long DEFAULT_FREQUENCY = 5000;
+
+ public static int DEFAULT_THRESHOLD = 3000;
+
+ private int _bufferedMessages = 0;
+
+ private int _threshold;
+
+ private long _lastMessageOutputTime;
+
+ private long _outputFrequencyInMillis;
+
+ public ProtocolBufferMonitorFilter()
+ {
+ _threshold = DEFAULT_THRESHOLD;
+ _outputFrequencyInMillis = DEFAULT_FREQUENCY;
+ }
+
+ public ProtocolBufferMonitorFilter(int threshold, long frequency)
+ {
+ _threshold = threshold;
+ _outputFrequencyInMillis = frequency;
+ }
+
+ public void messageReceived(NextFilter nextFilter, IoSession session, Object message) throws Exception
+ {
+ _bufferedMessages++;
+ if (_bufferedMessages > _threshold)
+ {
+ long now = System.currentTimeMillis();
+ if ((now - _lastMessageOutputTime) > _outputFrequencyInMillis)
+ {
+ _logger.warn("Protocol message buffer exceeded threshold of " + _threshold + ". Current backlog: "
+ + _bufferedMessages);
+ _lastMessageOutputTime = now;
+ }
+ }
+
+ nextFilter.messageReceived(session, message);
+ }
+
+ public void messageSent(NextFilter nextFilter, IoSession session, Object message) throws Exception
+ {
+ _bufferedMessages--;
+ nextFilter.messageSent(session, message);
+ }
+
+ public int getBufferedMessages()
+ {
+ return _bufferedMessages;
+ }
+
+ public int getThreshold()
+ {
+ return _threshold;
+ }
+
+ public void setThreshold(int threshold)
+ {
+ _threshold = threshold;
+ }
+
+ public long getOutputFrequencyInMillis()
+ {
+ return _outputFrequencyInMillis;
+ }
+
+ public void setOutputFrequencyInMillis(long outputFrequencyInMillis)
+ {
+ _outputFrequencyInMillis = outputFrequencyInMillis;
+ }
+
+ public long getLastMessageOutputTime()
+ {
+ return _lastMessageOutputTime;
+ }
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/client/security/AMQCallbackHandler.java b/Final/java/client/src/main/java/org/apache/qpid/client/security/AMQCallbackHandler.java
new file mode 100644
index 0000000000..fbca444208
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/security/AMQCallbackHandler.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.client.security;
+
+import javax.security.auth.callback.CallbackHandler;
+
+import org.apache.qpid.client.protocol.AMQProtocolSession;
+
+public interface AMQCallbackHandler extends CallbackHandler
+{
+ void initialise(AMQProtocolSession protocolSession);
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/client/security/CallbackHandlerRegistry.java b/Final/java/client/src/main/java/org/apache/qpid/client/security/CallbackHandlerRegistry.java
new file mode 100644
index 0000000000..140cbdeb75
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/security/CallbackHandlerRegistry.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.client.security;
+
+import org.apache.qpid.util.FileUtils;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+
+/**
+ * CallbackHandlerRegistry is a registry for call back handlers for user authentication and interaction during user
+ * authentication. It is capable of reading its configuration from a properties file containing call back handler
+ * implementing class names for different SASL mechanism names. Instantiating this registry also has the effect of
+ * configuring and registering the SASL client factory implementations using {@link DynamicSaslRegistrar}.
+ *
+ * <p/>The callback configuration should be specified in a properties file, refered to by the System property
+ * "amp.callbackhandler.properties". The format of the properties file is:
+ *
+ * <p/><pre>
+ * CallbackHanlder.mechanism=fully.qualified.class.name
+ * </pre>
+ *
+ * <p/>Where mechanism is an IANA-registered mechanism name and the fully qualified class name refers to a
+ * class that implements org.apache.qpid.client.security.AMQCallbackHanlder and provides a call back handler for the
+ * specified mechanism.
+ *
+ * <p><table id="crc"><caption>CRC Card</caption>
+ * <tr><th> Responsibilities <th> Collaborations
+ * <tr><td> Parse callback properties.
+ * <tr><td> Provide mapping from SASL mechanisms to callback implementations.
+ * </table>
+ */
+public class CallbackHandlerRegistry
+{
+ private static final Logger _logger = LoggerFactory.getLogger(CallbackHandlerRegistry.class);
+
+ /** The name of the system property that holds the name of the callback handler properties file. */
+ private static final String FILE_PROPERTY = "amq.callbackhandler.properties";
+
+ /** The default name of the callback handler properties resource. */
+ public static final String DEFAULT_RESOURCE_NAME = "org/apache/qpid/client/security/CallbackHandlerRegistry.properties";
+
+ /** A static reference to the singleton instance of this registry. */
+ private static CallbackHandlerRegistry _instance = new CallbackHandlerRegistry();
+
+ /** Holds a map from SASL mechanism names to call back handlers. */
+ private Map<String, Class> _mechanismToHandlerClassMap = new HashMap<String, Class>();
+
+ /** Holds a space delimited list of mechanisms that callback handlers exist for. */
+ private String _mechanisms;
+
+ /**
+ * Gets the singleton instance of this registry.
+ *
+ * @return The singleton instance of this registry.
+ */
+ public static CallbackHandlerRegistry getInstance()
+ {
+ return _instance;
+ }
+
+ /**
+ * Gets the callback handler class for a given SASL mechanism name.
+ *
+ * @param mechanism The SASL mechanism name.
+ *
+ * @return The callback handler class for the mechanism, or null if none is configured for that mechanism.
+ */
+ public Class getCallbackHandlerClass(String mechanism)
+ {
+ return (Class) _mechanismToHandlerClassMap.get(mechanism);
+ }
+
+ /**
+ * Gets a space delimited list of supported SASL mechanisms.
+ *
+ * @return A space delimited list of supported SASL mechanisms.
+ */
+ public String getMechanisms()
+ {
+ return _mechanisms;
+ }
+
+ /**
+ * Creates the call back handler registry from its configuration resource or file. This also has the side effect
+ * of configuring and registering the SASL client factory implementations using {@link DynamicSaslRegistrar}.
+ */
+ private CallbackHandlerRegistry()
+ {
+ // Register any configured SASL client factories.
+ DynamicSaslRegistrar.registerSaslProviders();
+
+ String filename = System.getProperty(FILE_PROPERTY);
+ InputStream is =
+ FileUtils.openFileOrDefaultResource(filename, DEFAULT_RESOURCE_NAME,
+ CallbackHandlerRegistry.class.getClassLoader());
+
+ try
+ {
+ Properties props = new Properties();
+ props.load(is);
+ parseProperties(props);
+ _logger.info("Callback handlers available for SASL mechanisms: " + _mechanisms);
+ }
+ catch (IOException e)
+ {
+ _logger.error("Error reading properties: " + e, e);
+ }
+ finally
+ {
+ if (is != null)
+ {
+ try
+ {
+ is.close();
+
+ }
+ catch (IOException e)
+ {
+ _logger.error("Unable to close properties stream: " + e, e);
+ }
+ }
+ }
+ }
+
+ /*private InputStream openPropertiesInputStream(String filename)
+ {
+ boolean useDefault = true;
+ InputStream is = null;
+ if (filename != null)
+ {
+ try
+ {
+ is = new BufferedInputStream(new FileInputStream(new File(filename)));
+ useDefault = false;
+ }
+ catch (FileNotFoundException e)
+ {
+ _logger.error("Unable to read from file " + filename + ": " + e, e);
+ }
+ }
+
+ if (useDefault)
+ {
+ is = CallbackHandlerRegistry.class.getResourceAsStream(DEFAULT_RESOURCE_NAME);
+ }
+
+ return is;
+ }*/
+
+ /**
+ * Scans the specified properties as a mapping from IANA registered SASL mechanism to call back handler
+ * implementations, that provide the necessary call back handling for obtaining user log in credentials
+ * during authentication for the specified mechanism, and builds a map from mechanism names to handler
+ * classes.
+ *
+ * @param props
+ */
+ private void parseProperties(Properties props)
+ {
+ Enumeration e = props.propertyNames();
+ while (e.hasMoreElements())
+ {
+ String propertyName = (String) e.nextElement();
+ int period = propertyName.indexOf(".");
+ if (period < 0)
+ {
+ _logger.warn("Unable to parse property " + propertyName + " when configuring SASL providers");
+
+ continue;
+ }
+
+ String mechanism = propertyName.substring(period + 1);
+ String className = props.getProperty(propertyName);
+ Class clazz = null;
+ try
+ {
+ clazz = Class.forName(className);
+ if (!AMQCallbackHandler.class.isAssignableFrom(clazz))
+ {
+ _logger.warn("SASL provider " + clazz + " does not implement " + AMQCallbackHandler.class
+ + ". Skipping");
+
+ continue;
+ }
+
+ _mechanismToHandlerClassMap.put(mechanism, clazz);
+ if (_mechanisms == null)
+ {
+ _mechanisms = mechanism;
+ }
+ else
+ {
+ // one time cost
+ _mechanisms = _mechanisms + " " + mechanism;
+ }
+ }
+ catch (ClassNotFoundException ex)
+ {
+ _logger.warn("Unable to load class " + className + ". Skipping that SASL provider");
+
+ continue;
+ }
+ }
+ }
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/client/security/CallbackHandlerRegistry.properties b/Final/java/client/src/main/java/org/apache/qpid/client/security/CallbackHandlerRegistry.properties
new file mode 100644
index 0000000000..89ee8337f8
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/security/CallbackHandlerRegistry.properties
@@ -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.
+#
+CallbackHandler.CRAM-MD5-HASHED=org.apache.qpid.client.security.UsernameHashedPasswordCallbackHandler
+CallbackHandler.CRAM-MD5=org.apache.qpid.client.security.UsernamePasswordCallbackHandler
+CallbackHandler.PLAIN=org.apache.qpid.client.security.UsernamePasswordCallbackHandler
diff --git a/Final/java/client/src/main/java/org/apache/qpid/client/security/DynamicSaslRegistrar.java b/Final/java/client/src/main/java/org/apache/qpid/client/security/DynamicSaslRegistrar.java
new file mode 100644
index 0000000000..803b34b7fa
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/security/DynamicSaslRegistrar.java
@@ -0,0 +1,198 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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.security;
+
+import org.apache.qpid.util.FileUtils;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.security.sasl.SaslClientFactory;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.Security;
+import java.util.Enumeration;
+import java.util.Map;
+import java.util.Properties;
+import java.util.TreeMap;
+
+/**
+ * DynamicSaslRegistrar provides a collection of helper methods for reading a configuration file that contains a mapping
+ * from SASL mechanism names to implementing client factory class names and registering a security provider with the
+ * Java runtime system, that uses the configured client factory implementations.
+ *
+ * <p/>The sasl configuration should be specified in a properties file, refered to by the System property
+ * "amp.dynamicsaslregistrar.properties". The format of the properties file is:
+ *
+ * <p/><pre>
+ * mechanism=fully.qualified.class.name
+ * </pre>
+ *
+ * <p/>Where mechanism is an IANA-registered mechanism name and the fully qualified class name refers to a class that
+ * implements javax.security.sasl.SaslClientFactory and provides the specified mechanism.
+ *
+ * <p><table id="crc"><caption>CRC Card</caption> <tr><th> Responsibilities <th> Collaborations <tr><td> Parse SASL
+ * mechanism properties. <tr><td> Create and register security provider for SASL mechanisms. </table>
+ */
+public class DynamicSaslRegistrar
+{
+ private static final Logger _logger = LoggerFactory.getLogger(DynamicSaslRegistrar.class);
+
+ /** The name of the system property that holds the name of the SASL configuration properties. */
+ private static final String FILE_PROPERTY = "amq.dynamicsaslregistrar.properties";
+
+ /** The default name of the SASL properties file resource. */
+ public static final String DEFAULT_RESOURCE_NAME = "org/apache/qpid/client/security/DynamicSaslRegistrar.properties";
+
+ /** Reads the properties file, and creates a dynamic security provider to register the SASL implementations with. */
+ public static void registerSaslProviders()
+ {
+ _logger.debug("public static void registerSaslProviders(): called");
+
+ // Open the SASL properties file, using the default name is one is not specified.
+ String filename = System.getProperty(FILE_PROPERTY);
+ InputStream is =
+ FileUtils.openFileOrDefaultResource(filename, DEFAULT_RESOURCE_NAME,
+ DynamicSaslRegistrar.class.getClassLoader());
+
+ try
+ {
+ Properties props = new Properties();
+ props.load(is);
+
+ _logger.debug("props = " + props);
+
+ Map<String, Class<? extends SaslClientFactory>> factories = parseProperties(props);
+
+ if (factories.size() > 0)
+ {
+ Security.insertProviderAt(new JCAProvider(factories), 0);
+ _logger.debug("Dynamic SASL provider added as a security provider");
+ }
+ }
+ catch (IOException e)
+ {
+ _logger.error("Error reading properties: " + e, e);
+ }
+ finally
+ {
+ if (is != null)
+ {
+ try
+ {
+ is.close();
+
+ }
+ catch (IOException e)
+ {
+ _logger.error("Unable to close properties stream: " + e, e);
+ }
+ }
+ }
+ }
+
+ /**
+ * Either attempts to open the specified filename as an input stream, or uses the default SASL configuration
+ * resource.
+ *
+ * @param filename The name of the file to get the SASL properties from, null to use the default.
+ *
+ * @return An input stream to read the dynamic SASL configuration from, or null if one could not be opened.
+ */
+ /*private static InputStream openPropertiesInputStream(String filename)
+ {
+ InputStream is = null;
+
+ // Flag to indicate whether the default resource should be used. By default this is true, so that the default
+ // is used when opening the file fails.
+ boolean useDefault = true;
+
+ // Try to open the file if one was specified.
+ if (filename != null)
+ {
+ try
+ {
+ is = new BufferedInputStream(new FileInputStream(new File(filename)));
+
+ // Clear the default flag because the file was succesfully opened.
+ useDefault = false;
+ }
+ catch (FileNotFoundException e)
+ {
+ _logger.error("Unable to read from file " + filename + ": " + e, e);
+ }
+ }
+
+ // Load the default resource if a file was not specified, or if opening the file failed.
+ if (useDefault)
+ {
+ is = CallbackHandlerRegistry.class.getResourceAsStream(DEFAULT_RESOURCE_NAME);
+ }
+
+ return is;
+ }*/
+
+ /**
+ * Parses the specified properties as a mapping from IANA registered SASL mechanism names to implementing client
+ * factories. If the client factories cannot be instantiated or do not implement SaslClientFactory then the
+ * properties refering to them are ignored.
+ *
+ * @param props The properties to scan for Sasl client factory implementations.
+ *
+ * @return A map from SASL mechanism names to implementing client factory classes.
+ *
+ * @todo Why tree map here? Do really want mechanisms in alphabetical order? Seems more likely that the declared
+ * order of the mechanisms is intended to be preserved, so that they are registered in the declared order of
+ * preference. Consider LinkedHashMap instead.
+ */
+ private static Map<String, Class<? extends SaslClientFactory>> parseProperties(Properties props)
+ {
+ Enumeration e = props.propertyNames();
+
+ TreeMap<String, Class<? extends SaslClientFactory>> factoriesToRegister =
+ new TreeMap<String, Class<? extends SaslClientFactory>>();
+
+ while (e.hasMoreElements())
+ {
+ String mechanism = (String) e.nextElement();
+ String className = props.getProperty(mechanism);
+ try
+ {
+ Class<?> clazz = Class.forName(className);
+ if (!(SaslClientFactory.class.isAssignableFrom(clazz)))
+ {
+ _logger.error("Class " + clazz + " does not implement " + SaslClientFactory.class + " - skipping");
+
+ continue;
+ }
+
+ factoriesToRegister.put(mechanism, (Class<? extends SaslClientFactory>) clazz);
+ }
+ catch (Exception ex)
+ {
+ _logger.error("Error instantiating SaslClientFactory calss " + className + " - skipping");
+ }
+ }
+
+ return factoriesToRegister;
+ }
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/client/security/DynamicSaslRegistrar.properties b/Final/java/client/src/main/java/org/apache/qpid/client/security/DynamicSaslRegistrar.properties
new file mode 100644
index 0000000000..1bff43142b
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/security/DynamicSaslRegistrar.properties
@@ -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.
+#
+AMQPLAIN=org.apache.qpid.client.security.amqplain.AmqPlainSaslClientFactory
+CRAM-MD5-HASHED=org.apache.qpid.client.security.crammd5hashed.CRAMMD5HashedSaslClientFactory
diff --git a/Final/java/client/src/main/java/org/apache/qpid/client/security/JCAProvider.java b/Final/java/client/src/main/java/org/apache/qpid/client/security/JCAProvider.java
new file mode 100644
index 0000000000..5a2c5ac5c1
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/security/JCAProvider.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.client.security;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.security.sasl.SaslClientFactory;
+
+import java.security.Provider;
+import java.util.Map;
+
+/**
+ * JCAProvider is a security provider for SASL client factories that is configured from a map of SASL mechanism names
+ * to client factories implementation class names. It is intended that the map of client factories can be read from a
+ * configuration file or other application configuration mechanism.
+ *
+ * <p><table id="crc"><caption>CRC Card</caption>
+ * <tr><th> Responsibilities <th> Collaborations
+ * <tr><td> Register SASL mechanism implementations.
+ * </table>
+ */
+public class JCAProvider extends Provider
+{
+ private static final Logger log = LoggerFactory.getLogger(JCAProvider.class);
+
+ /**
+ * 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);
+ // Security.addProvider(this);
+ }
+
+ /**
+ * 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());
+ log.debug("Registered SASL Client factory for " + me.getKey() + " as " + me.getValue().getName());
+ }
+ }
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/client/security/UsernameHashedPasswordCallbackHandler.java b/Final/java/client/src/main/java/org/apache/qpid/client/security/UsernameHashedPasswordCallbackHandler.java
new file mode 100644
index 0000000000..66176dac3c
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/security/UsernameHashedPasswordCallbackHandler.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.client.security;
+
+import org.apache.qpid.client.protocol.AMQProtocolSession;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+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.io.UnsupportedEncodingException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+
+public class UsernameHashedPasswordCallbackHandler implements AMQCallbackHandler
+{
+ private static final Logger _logger = LoggerFactory.getLogger(UsernameHashedPasswordCallbackHandler.class);
+
+ private AMQProtocolSession _protocolSession;
+
+ public void initialise(AMQProtocolSession protocolSession)
+ {
+ _protocolSession = protocolSession;
+ }
+
+ public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException
+ {
+ for (int i = 0; i < callbacks.length; i++)
+ {
+ Callback cb = callbacks[i];
+ if (cb instanceof NameCallback)
+ {
+ ((NameCallback) cb).setName(_protocolSession.getUsername());
+ }
+ else if (cb instanceof PasswordCallback)
+ {
+ try
+ {
+ ((PasswordCallback) cb).setPassword(getHash(_protocolSession.getPassword()));
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ UnsupportedCallbackException uce = new UnsupportedCallbackException(cb);
+ uce.initCause(e);
+ throw uce;
+ }
+ }
+ else
+ {
+ throw new UnsupportedCallbackException(cb);
+ }
+ }
+ }
+
+ private 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/Final/java/client/src/main/java/org/apache/qpid/client/security/UsernamePasswordCallbackHandler.java b/Final/java/client/src/main/java/org/apache/qpid/client/security/UsernamePasswordCallbackHandler.java
new file mode 100644
index 0000000000..c50c62710f
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/security/UsernamePasswordCallbackHandler.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.client.security;
+
+import java.io.IOException;
+
+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 org.apache.qpid.client.protocol.AMQProtocolSession;
+
+public class UsernamePasswordCallbackHandler implements AMQCallbackHandler
+{
+ private AMQProtocolSession _protocolSession;
+
+ public void initialise(AMQProtocolSession protocolSession)
+ {
+ _protocolSession = protocolSession;
+ }
+
+ public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException
+ {
+ for (int i = 0; i < callbacks.length; i++)
+ {
+ Callback cb = callbacks[i];
+ if (cb instanceof NameCallback)
+ {
+ ((NameCallback)cb).setName(_protocolSession.getUsername());
+ }
+ else if (cb instanceof PasswordCallback)
+ {
+ ((PasswordCallback)cb).setPassword(_protocolSession.getPassword().toCharArray());
+ }
+ else
+ {
+ throw new UnsupportedCallbackException(cb);
+ }
+ }
+ }
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/client/security/amqplain/AmqPlainSaslClient.java b/Final/java/client/src/main/java/org/apache/qpid/client/security/amqplain/AmqPlainSaslClient.java
new file mode 100644
index 0000000000..f8a25c630c
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/security/amqplain/AmqPlainSaslClient.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.client.security.amqplain;
+
+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.sasl.SaslClient;
+import javax.security.sasl.SaslException;
+
+import org.apache.qpid.framing.FieldTable;
+import org.apache.qpid.framing.FieldTableFactory;
+
+/**
+ * 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/Final/java/client/src/main/java/org/apache/qpid/client/security/amqplain/AmqPlainSaslClientFactory.java b/Final/java/client/src/main/java/org/apache/qpid/client/security/amqplain/AmqPlainSaslClientFactory.java
new file mode 100644
index 0000000000..30cc786890
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/security/amqplain/AmqPlainSaslClientFactory.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.security.amqplain;
+
+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 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/Final/java/client/src/main/java/org/apache/qpid/client/security/crammd5hashed/CRAMMD5HashedSaslClientFactory.java b/Final/java/client/src/main/java/org/apache/qpid/client/security/crammd5hashed/CRAMMD5HashedSaslClientFactory.java
new file mode 100644
index 0000000000..22bb1ac156
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/security/crammd5hashed/CRAMMD5HashedSaslClientFactory.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.client.security.crammd5hashed;
+
+import org.apache.qpid.client.security.amqplain.AmqPlainSaslClient;
+
+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;
+import java.security.Security;
+
+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)
+ {
+ 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[]{MECHANISM};
+ }
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/client/state/AMQState.java b/Final/java/client/src/main/java/org/apache/qpid/client/state/AMQState.java
new file mode 100644
index 0000000000..4996f59345
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/state/AMQState.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.state;
+
+/**
+ * States used in the AMQ protocol. Used by the finite state machine to determine
+ * valid responses.
+ */
+public class AMQState
+{
+ private final int _id;
+
+ private final String _name;
+
+ private AMQState(int id, String name)
+ {
+ _id = id;
+ _name = name;
+ }
+
+ public String toString()
+ {
+ return "AMQState: id = " + _id + " name: " + _name;
+ }
+
+ public static final AMQState CONNECTION_NOT_STARTED = new AMQState(1, "CONNECTION_NOT_STARTED");
+
+ public static final AMQState CONNECTION_NOT_TUNED = new AMQState(2, "CONNECTION_NOT_TUNED");
+
+ public static final AMQState CONNECTION_NOT_OPENED = new AMQState(3, "CONNECTION_NOT_OPENED");
+
+ public static final AMQState CONNECTION_OPEN = new AMQState(4, "CONNECTION_OPEN");
+
+ public static final AMQState CONNECTION_CLOSING = new AMQState(5, "CONNECTION_CLOSING");
+
+ public static final AMQState CONNECTION_CLOSED = new AMQState(6, "CONNECTION_CLOSED");
+
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/client/state/AMQStateChangedEvent.java b/Final/java/client/src/main/java/org/apache/qpid/client/state/AMQStateChangedEvent.java
new file mode 100644
index 0000000000..edef54ccd6
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/state/AMQStateChangedEvent.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.client.state;
+
+/**
+ * An event that is fired when the protocol state has changed.
+ *
+ */
+public class AMQStateChangedEvent
+{
+ private final AMQState _oldState;
+
+ private final AMQState _newState;
+
+ public AMQStateChangedEvent(AMQState oldState, AMQState newState)
+ {
+ _oldState = oldState;
+ _newState = newState;
+ }
+
+ public AMQState getOldState()
+ {
+ return _oldState;
+ }
+
+ public AMQState getNewState()
+ {
+ return _newState;
+ }
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/client/state/AMQStateListener.java b/Final/java/client/src/main/java/org/apache/qpid/client/state/AMQStateListener.java
new file mode 100644
index 0000000000..110471aad0
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/state/AMQStateListener.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.client.state;
+
+public interface AMQStateListener
+{
+ void stateChanged(AMQStateChangedEvent evt);
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/client/state/AMQStateManager.java b/Final/java/client/src/main/java/org/apache/qpid/client/state/AMQStateManager.java
new file mode 100644
index 0000000000..227f23b540
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/state/AMQStateManager.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.client.state;
+
+import org.apache.qpid.AMQException;
+import org.apache.qpid.client.handler.BasicCancelOkMethodHandler;
+import org.apache.qpid.client.handler.BasicDeliverMethodHandler;
+import org.apache.qpid.client.handler.BasicReturnMethodHandler;
+import org.apache.qpid.client.handler.ChannelCloseMethodHandler;
+import org.apache.qpid.client.handler.ChannelCloseOkMethodHandler;
+import org.apache.qpid.client.handler.ChannelFlowOkMethodHandler;
+import org.apache.qpid.client.handler.ConnectionCloseMethodHandler;
+import org.apache.qpid.client.handler.ConnectionOpenOkMethodHandler;
+import org.apache.qpid.client.handler.ConnectionSecureMethodHandler;
+import org.apache.qpid.client.handler.ConnectionStartMethodHandler;
+import org.apache.qpid.client.handler.ConnectionTuneMethodHandler;
+import org.apache.qpid.client.handler.ExchangeBoundOkMethodHandler;
+import org.apache.qpid.client.handler.QueueDeleteOkMethodHandler;
+import org.apache.qpid.client.protocol.AMQProtocolSession;
+import org.apache.qpid.framing.AMQMethodBody;
+import org.apache.qpid.framing.BasicCancelOkBody;
+import org.apache.qpid.framing.BasicDeliverBody;
+import org.apache.qpid.framing.BasicReturnBody;
+import org.apache.qpid.framing.ChannelCloseBody;
+import org.apache.qpid.framing.ChannelCloseOkBody;
+import org.apache.qpid.framing.ChannelFlowOkBody;
+import org.apache.qpid.framing.ConnectionCloseBody;
+import org.apache.qpid.framing.ConnectionOpenOkBody;
+import org.apache.qpid.framing.ConnectionSecureBody;
+import org.apache.qpid.framing.ConnectionStartBody;
+import org.apache.qpid.framing.ConnectionTuneBody;
+import org.apache.qpid.framing.ExchangeBoundOkBody;
+import org.apache.qpid.framing.QueueDeleteOkBody;
+import org.apache.qpid.protocol.AMQMethodEvent;
+import org.apache.qpid.protocol.AMQMethodListener;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.concurrent.CopyOnWriteArraySet;
+
+/**
+ * The state manager is responsible for managing the state of the protocol session. <p/> For each AMQProtocolHandler
+ * there is a separate state manager.
+ */
+public class AMQStateManager implements AMQMethodListener
+{
+ private static final Logger _logger = LoggerFactory.getLogger(AMQStateManager.class);
+
+ private AMQProtocolSession _protocolSession;
+
+ /** The current state */
+ private AMQState _currentState;
+
+ /**
+ * Maps from an AMQState instance to a Map from Class to StateTransitionHandler. The class must be a subclass of
+ * AMQFrame.
+ */
+ protected final Map _state2HandlersMap = new HashMap();
+
+ private final CopyOnWriteArraySet _stateListeners = new CopyOnWriteArraySet();
+ private final Object _stateLock = new Object();
+ private static final long MAXIMUM_STATE_WAIT_TIME = 30000L;
+
+ public AMQStateManager()
+ {
+ this(null);
+ }
+
+ public AMQStateManager(AMQProtocolSession protocolSession)
+ {
+ this(AMQState.CONNECTION_NOT_STARTED, true, protocolSession);
+ }
+
+ protected AMQStateManager(AMQState state, boolean register, AMQProtocolSession protocolSession)
+ {
+ _protocolSession = protocolSession;
+ _currentState = state;
+ if (register)
+ {
+ registerListeners();
+ }
+ }
+
+ protected void registerListeners()
+ {
+ Map frame2handlerMap = new HashMap();
+
+ // we need to register a map for the null (i.e. all state) handlers otherwise you get
+ // a stack overflow in the handler searching code when you present it with a frame for which
+ // no handlers are registered
+ //
+ _state2HandlersMap.put(null, frame2handlerMap);
+
+ frame2handlerMap = new HashMap();
+ frame2handlerMap.put(ConnectionStartBody.class, ConnectionStartMethodHandler.getInstance());
+ frame2handlerMap.put(ConnectionCloseBody.class, ConnectionCloseMethodHandler.getInstance());
+ _state2HandlersMap.put(AMQState.CONNECTION_NOT_STARTED, frame2handlerMap);
+
+ frame2handlerMap = new HashMap();
+ frame2handlerMap.put(ConnectionTuneBody.class, ConnectionTuneMethodHandler.getInstance());
+ frame2handlerMap.put(ConnectionSecureBody.class, ConnectionSecureMethodHandler.getInstance());
+ frame2handlerMap.put(ConnectionCloseBody.class, ConnectionCloseMethodHandler.getInstance());
+ _state2HandlersMap.put(AMQState.CONNECTION_NOT_TUNED, frame2handlerMap);
+
+ frame2handlerMap = new HashMap();
+ frame2handlerMap.put(ConnectionOpenOkBody.class, ConnectionOpenOkMethodHandler.getInstance());
+ frame2handlerMap.put(ConnectionCloseBody.class, ConnectionCloseMethodHandler.getInstance());
+ _state2HandlersMap.put(AMQState.CONNECTION_NOT_OPENED, frame2handlerMap);
+
+ //
+ // ConnectionOpen handlers
+ //
+ frame2handlerMap = new HashMap();
+ frame2handlerMap.put(ChannelCloseBody.class, ChannelCloseMethodHandler.getInstance());
+ frame2handlerMap.put(ChannelCloseOkBody.class, ChannelCloseOkMethodHandler.getInstance());
+ frame2handlerMap.put(ConnectionCloseBody.class, ConnectionCloseMethodHandler.getInstance());
+ frame2handlerMap.put(BasicDeliverBody.class, BasicDeliverMethodHandler.getInstance());
+ frame2handlerMap.put(BasicReturnBody.class, BasicReturnMethodHandler.getInstance());
+ frame2handlerMap.put(BasicCancelOkBody.class, BasicCancelOkMethodHandler.getInstance());
+ frame2handlerMap.put(ChannelFlowOkBody.class, ChannelFlowOkMethodHandler.getInstance());
+ frame2handlerMap.put(QueueDeleteOkBody.class, QueueDeleteOkMethodHandler.getInstance());
+ frame2handlerMap.put(ExchangeBoundOkBody.class, ExchangeBoundOkMethodHandler.getInstance());
+ _state2HandlersMap.put(AMQState.CONNECTION_OPEN, frame2handlerMap);
+ }
+
+ public AMQState getCurrentState()
+ {
+ return _currentState;
+ }
+
+ public void changeState(AMQState newState) throws AMQException
+ {
+ _logger.debug("State changing to " + newState + " from old state " + _currentState);
+
+ synchronized (_stateLock)
+ {
+ _currentState = newState;
+ _stateLock.notifyAll();
+ }
+ }
+
+ public void error(Exception e)
+ {
+ _logger.debug("State manager receive error notification: " + e);
+ synchronized (_stateListeners)
+ {
+ final Iterator it = _stateListeners.iterator();
+ while (it.hasNext())
+ {
+ final StateListener l = (StateListener) it.next();
+ l.error(e);
+ }
+ }
+ }
+
+ public <B extends AMQMethodBody> boolean methodReceived(AMQMethodEvent<B> evt) throws AMQException
+ {
+ StateAwareMethodListener handler = findStateTransitionHandler(_currentState, evt.getMethod());
+ if (handler != null)
+ {
+ handler.methodReceived(this, _protocolSession, evt);
+
+ return true;
+ }
+
+ return false;
+ }
+
+ protected StateAwareMethodListener findStateTransitionHandler(AMQState currentState, AMQMethodBody frame)
+ // throws IllegalStateTransitionException
+ {
+ final Class clazz = frame.getClass();
+ if (_logger.isDebugEnabled())
+ {
+ _logger.debug("Looking for state[" + currentState + "] transition handler for frame " + clazz);
+ }
+
+ final Map classToHandlerMap = (Map) _state2HandlersMap.get(currentState);
+
+ if (classToHandlerMap == null)
+ {
+ // if no specialised per state handler is registered look for a
+ // handler registered for "all" states
+ return findStateTransitionHandler(null, frame);
+ }
+
+ final StateAwareMethodListener handler = (StateAwareMethodListener) classToHandlerMap.get(clazz);
+ if (handler == null)
+ {
+ if (currentState == null)
+ {
+ _logger.debug("No state transition handler defined for receiving frame " + frame);
+
+ return null;
+ }
+ else
+ {
+ // if no specialised per state handler is registered look for a
+ // handler registered for "all" states
+ return findStateTransitionHandler(null, frame);
+ }
+ }
+ else
+ {
+ return handler;
+ }
+ }
+
+ public void attainState(final AMQState s) throws AMQException
+ {
+ synchronized (_stateLock)
+ {
+ final long waitUntilTime = System.currentTimeMillis() + MAXIMUM_STATE_WAIT_TIME;
+ long waitTime = MAXIMUM_STATE_WAIT_TIME;
+
+ while ((_currentState != s) && (waitTime > 0))
+ {
+ try
+ {
+ _stateLock.wait(MAXIMUM_STATE_WAIT_TIME);
+ }
+ catch (InterruptedException e)
+ {
+ _logger.warn("Thread interrupted");
+ }
+
+ if (_currentState != s)
+ {
+ waitTime = waitUntilTime - System.currentTimeMillis();
+ }
+ }
+
+ if (_currentState != s)
+ {
+ _logger.warn("State not achieved within permitted time. Current state " + _currentState
+ + ", desired state: " + s);
+ throw new AMQException("State not achieved within permitted time. Current state " + _currentState
+ + ", desired state: " + s);
+ }
+ }
+
+ // at this point the state will have changed.
+ }
+
+ public AMQProtocolSession getProtocolSession()
+ {
+ return _protocolSession;
+ }
+
+ public void setProtocolSession(AMQProtocolSession session)
+ {
+ _protocolSession = session;
+ }
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/client/state/IllegalStateTransitionException.java b/Final/java/client/src/main/java/org/apache/qpid/client/state/IllegalStateTransitionException.java
new file mode 100644
index 0000000000..41fa1ba704
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/state/IllegalStateTransitionException.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.client.state;
+
+import org.apache.qpid.AMQException;
+
+/**
+ * @todo Not an AMQP exception as no status code.
+ *
+ * @todo Not used! Delete.
+ */
+public class IllegalStateTransitionException extends AMQException
+{
+ private AMQState _originalState;
+
+ private Class _frame;
+
+ public IllegalStateTransitionException(AMQState originalState, Class frame)
+ {
+ super("No valid state transition defined for receiving frame " + frame +
+ " from state " + originalState);
+ _originalState = originalState;
+ _frame = frame;
+ }
+
+ public AMQState getOriginalState()
+ {
+ return _originalState;
+ }
+
+ public Class getFrameClass()
+ {
+ return _frame;
+ }
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/client/state/StateAwareMethodListener.java b/Final/java/client/src/main/java/org/apache/qpid/client/state/StateAwareMethodListener.java
new file mode 100644
index 0000000000..b3932533ce
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/state/StateAwareMethodListener.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.client.state;
+
+import org.apache.qpid.AMQException;
+import org.apache.qpid.client.protocol.AMQProtocolSession;
+import org.apache.qpid.protocol.AMQMethodEvent;
+
+/**
+ * A frame listener that is informed of the protocl state when invoked and has
+ * the opportunity to update state.
+ *
+ */
+public interface StateAwareMethodListener
+{
+ void methodReceived(AMQStateManager stateManager, AMQProtocolSession protocolSession,
+ AMQMethodEvent evt) throws AMQException;
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/client/state/StateListener.java b/Final/java/client/src/main/java/org/apache/qpid/client/state/StateListener.java
new file mode 100644
index 0000000000..df207a0a23
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/state/StateListener.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.client.state;
+
+import org.apache.qpid.AMQException;
+
+public interface StateListener
+{
+ void stateChanged(AMQState oldState, AMQState newState) throws AMQException;
+
+ void error(Throwable t);
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/client/state/StateWaiter.java b/Final/java/client/src/main/java/org/apache/qpid/client/state/StateWaiter.java
new file mode 100644
index 0000000000..73d5a8a3d6
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/state/StateWaiter.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.client.state;
+
+import org.apache.qpid.AMQException;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Waits for a particular state to be reached.
+ */
+public class StateWaiter implements StateListener
+{
+ private static final Logger _logger = LoggerFactory.getLogger(StateWaiter.class);
+
+ private final AMQState _state;
+
+ private volatile boolean _newStateAchieved;
+
+ private volatile Throwable _throwable;
+
+ private final Object _monitor = new Object();
+ private static final long TIME_OUT = 1000 * 60 * 2;
+
+ public StateWaiter(AMQState state)
+ {
+ _state = state;
+ }
+
+ public void waituntilStateHasChanged() throws AMQException
+ {
+ synchronized (_monitor)
+ {
+ //
+ // The guard is required in case we are woken up by a spurious
+ // notify().
+ //
+ while (!_newStateAchieved && (_throwable == null))
+ {
+ try
+ {
+ _logger.debug("State " + _state + " not achieved so waiting...");
+ _monitor.wait(TIME_OUT);
+ // fixme this won't cause the timeout to exit the loop. need to set _throwable
+ }
+ catch (InterruptedException e)
+ {
+ _logger.debug("Interrupted exception caught while waiting: " + e, e);
+ }
+ }
+ }
+
+ if (_throwable != null)
+ {
+ _logger.debug("Throwable reached state waiter: " + _throwable);
+ if (_throwable instanceof AMQException)
+ {
+ throw (AMQException) _throwable;
+ }
+ else
+ {
+ throw new AMQException("Error: " + _throwable, _throwable); // FIXME: this will wrap FailoverException in throwable which will prevent it being caught.
+ }
+ }
+ }
+
+ public void stateChanged(AMQState oldState, AMQState newState)
+ {
+ synchronized (_monitor)
+ {
+ if (_logger.isDebugEnabled())
+ {
+ _logger.debug("stateChanged called changing from :" + oldState + " to :" + newState);
+ }
+
+ if (_state == newState)
+ {
+ _newStateAchieved = true;
+
+ if (_logger.isDebugEnabled())
+ {
+ _logger.debug("New state reached so notifying monitor");
+ }
+
+ _monitor.notifyAll();
+ }
+ }
+ }
+
+ public void error(Throwable t)
+ {
+ synchronized (_monitor)
+ {
+ if (_logger.isDebugEnabled())
+ {
+ _logger.debug("exceptionThrown called");
+ }
+
+ _throwable = t;
+ _monitor.notifyAll();
+ }
+ }
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/client/state/listener/SpecificMethodFrameListener.java b/Final/java/client/src/main/java/org/apache/qpid/client/state/listener/SpecificMethodFrameListener.java
new file mode 100644
index 0000000000..4a4f4a0a38
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/state/listener/SpecificMethodFrameListener.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.client.state.listener;
+
+import org.apache.qpid.AMQException;
+import org.apache.qpid.client.protocol.BlockingMethodFrameListener;
+import org.apache.qpid.framing.AMQMethodBody;
+
+public class SpecificMethodFrameListener extends BlockingMethodFrameListener
+{
+ private final Class _expectedClass;
+
+ public SpecificMethodFrameListener(int channelId, Class expectedClass)
+ {
+ super(channelId);
+ _expectedClass = expectedClass;
+ }
+
+ public boolean processMethod(int channelId, AMQMethodBody frame) //throws AMQException
+ {
+
+ //equiv to: (frame instanceof _expectedClass)
+ return _expectedClass.isInstance(frame);
+ }
+
+ public boolean equals(Object o)
+ {
+ if (o instanceof SpecificMethodFrameListener)
+ {
+ SpecificMethodFrameListener other = (SpecificMethodFrameListener) o;
+
+ // here we need to check if the two classes are the same.
+ return (_channelId == other._channelId) && (_expectedClass.equals(other._expectedClass));
+ }
+
+ return false;
+ }
+
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/client/transport/AMQNoTransportForProtocolException.java b/Final/java/client/src/main/java/org/apache/qpid/client/transport/AMQNoTransportForProtocolException.java
new file mode 100644
index 0000000000..da16baaad9
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/transport/AMQNoTransportForProtocolException.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.client.transport;
+
+import org.apache.qpid.jms.BrokerDetails;
+
+/**
+ * AMQNoTransportForProtocolException represents a connection failure where there is no transport medium to connect
+ * to the broker available. This may be the case if their is a error in the connection url, or an unsupported transport
+ * type is specified.
+ *
+ * <p/><table id="crc"><caption>CRC Card</caption>
+ * <tr><th> Responsibilities <th> Collaborations
+ * <tr><td> Represent absence of a transport medium.
+ * </table>
+ */
+public class AMQNoTransportForProtocolException extends AMQTransportConnectionException
+{
+ BrokerDetails _details;
+
+ public AMQNoTransportForProtocolException(BrokerDetails details)
+ {
+ this(details, "No Transport exists for specified broker protocol");
+ }
+
+ public AMQNoTransportForProtocolException(BrokerDetails details, String message)
+ {
+ super(null, message, null);
+
+ _details = details;
+ }
+
+ public String toString()
+ {
+ if (_details != null)
+ {
+ return super.toString() + _details.toString();
+ }
+ else
+ {
+ return super.toString();
+ }
+ }
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/client/transport/AMQTransportConnectionException.java b/Final/java/client/src/main/java/org/apache/qpid/client/transport/AMQTransportConnectionException.java
new file mode 100644
index 0000000000..24b4e03b39
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/transport/AMQTransportConnectionException.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.client.transport;
+
+import org.apache.qpid.AMQException;
+import org.apache.qpid.protocol.AMQConstant;
+
+/**
+ * AMQTransportConnectionException indicates a failure to establish a connection through the transporting medium, to
+ * an AMQP broker.
+ *
+ * <p/><table id="crc"><caption>CRC Card</caption>
+ * <tr><th> Responsibilities <th> Collaborations
+ * <tr><td> Represent failure to connect through the transport medium.
+ * </table>
+ */
+public class AMQTransportConnectionException extends AMQException
+{
+ public AMQTransportConnectionException(AMQConstant errorCode, String message, Throwable cause)
+ {
+ super(errorCode, message, cause);
+ }
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/client/transport/ITransportConnection.java b/Final/java/client/src/main/java/org/apache/qpid/client/transport/ITransportConnection.java
new file mode 100644
index 0000000000..7a24d6e15a
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/transport/ITransportConnection.java
@@ -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.
+ *
+ */
+package org.apache.qpid.client.transport;
+
+import java.io.IOException;
+
+import org.apache.qpid.client.protocol.AMQProtocolHandler;
+import org.apache.qpid.jms.BrokerDetails;
+
+public interface ITransportConnection
+{
+ void connect(AMQProtocolHandler protocolHandler, BrokerDetails brokerDetail)
+ throws IOException;
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/client/transport/SocketTransportConnection.java b/Final/java/client/src/main/java/org/apache/qpid/client/transport/SocketTransportConnection.java
new file mode 100644
index 0000000000..5482e48699
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/transport/SocketTransportConnection.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.client.transport;
+
+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.SocketConnectorConfig;
+import org.apache.mina.transport.socket.nio.SocketSessionConfig;
+
+import org.apache.qpid.client.protocol.AMQProtocolHandler;
+import org.apache.qpid.jms.BrokerDetails;
+import org.apache.qpid.pool.ReadWriteThreadModel;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+
+public class SocketTransportConnection implements ITransportConnection
+{
+ private static final Logger _logger = LoggerFactory.getLogger(SocketTransportConnection.class);
+ private static final int DEFAULT_BUFFER_SIZE = 32 * 1024;
+
+ private SocketConnectorFactory _socketConnectorFactory;
+
+ static interface SocketConnectorFactory
+ {
+ IoConnector newSocketConnector();
+ }
+
+ public SocketTransportConnection(SocketConnectorFactory socketConnectorFactory)
+ {
+ _socketConnectorFactory = socketConnectorFactory;
+ }
+
+ public void connect(AMQProtocolHandler protocolHandler, BrokerDetails brokerDetail) throws IOException
+ {
+ 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"))
+ {
+ _logger.info("Using SimpleByteBufferAllocator");
+ ByteBuffer.setAllocator(new SimpleByteBufferAllocator());
+ }
+
+ 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 = 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
+ {
+ throw new IOException("Timeout waiting for connection.");
+ }
+ }
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/client/transport/TransportConnection.java b/Final/java/client/src/main/java/org/apache/qpid/client/transport/TransportConnection.java
new file mode 100644
index 0000000000..1d0d6a3491
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/transport/TransportConnection.java
@@ -0,0 +1,318 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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.transport;
+
+import org.apache.mina.common.IoConnector;
+import org.apache.mina.common.IoHandlerAdapter;
+import org.apache.mina.common.IoServiceConfig;
+import org.apache.mina.transport.socket.nio.SocketConnector;
+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.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+/**
+ * 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
+ * protocol events. <p/> Could be extended in future to support different transport types by turning this into concrete
+ * class/interface combo.
+ */
+public class TransportConnection
+{
+ private static ITransportConnection _instance;
+
+ private static Map _inVmPipeAddress = new HashMap();
+ private static VmPipeAcceptor _acceptor;
+ private static int _currentInstance = -1;
+ private static int _currentVMPort = -1;
+
+ private static final int TCP = 0;
+ private static final int VM = 1;
+
+ private static Logger _logger = LoggerFactory.getLogger(TransportConnection.class);
+
+ private static final String DEFAULT_QPID_SERVER = "org.apache.qpid.server.protocol.AMQPFastProtocolHandler";
+
+ public static ITransportConnection getInstance(BrokerDetails details) throws AMQTransportConnectionException
+ {
+ int transport = getTransport(details.getTransport());
+
+ if (transport == -1)
+ {
+ throw new AMQNoTransportForProtocolException(details);
+ }
+
+ if (transport == _currentInstance)
+ {
+ if (transport == VM)
+ {
+ if (_currentVMPort == details.getPort())
+ {
+ return _instance;
+ }
+ }
+ else
+ {
+ return _instance;
+ }
+ }
+
+ _currentInstance = transport;
+
+ switch (transport)
+ {
+
+ case TCP:
+ _instance = new SocketTransportConnection(new SocketTransportConnection.SocketConnectorFactory()
+ {
+ public IoConnector newSocketConnector()
+ {
+ SocketConnector result;
+ // FIXME - this needs to be sorted to use the new Mina MultiThread SA.
+ if (Boolean.getBoolean("qpidnio"))
+ {
+ _logger.error("Using Qpid NIO - sysproperty 'qpidnio' is set.");
+ // result = new org.apache.qpid.nio.SocketConnector(); // non-blocking connector
+ }
+ // else
+
+ {
+ _logger.info("Using Mina NIO");
+ result = new SocketConnector(); // 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
+ // clients (like unit tests) to complete quickly.
+ result.setWorkerTimeout(0);
+
+ return result;
+ }
+ });
+ break;
+
+ case VM:
+ {
+ _instance = getVMTransport(details, Boolean.getBoolean("amqj.AutoCreateVMBroker"));
+ break;
+ }
+ }
+
+ return _instance;
+ }
+
+ private static int getTransport(String transport)
+ {
+ if (transport.equals(BrokerDetails.TCP))
+ {
+ return TCP;
+ }
+
+ if (transport.equals(BrokerDetails.VM))
+ {
+ return VM;
+ }
+
+ return -1;
+ }
+
+ private static ITransportConnection getVMTransport(BrokerDetails details, boolean AutoCreate)
+ throws AMQVMBrokerCreationException
+ {
+ int port = details.getPort();
+
+ synchronized (_inVmPipeAddress)
+ {
+ if (!_inVmPipeAddress.containsKey(port))
+ {
+ if (AutoCreate)
+ {
+ createVMBroker(port);
+ }
+ else
+ {
+ throw new AMQVMBrokerCreationException(null, port, "VM Broker on port " + port
+ + " does not exist. Auto create disabled.", null);
+ }
+ }
+ }
+ return new VmPipeTransportConnection(port);
+ }
+
+ public static void createVMBroker(int port) throws AMQVMBrokerCreationException
+ {
+ if (_acceptor == null)
+ {
+ _acceptor = new VmPipeAcceptor();
+
+ IoServiceConfig config = _acceptor.getDefaultConfig();
+
+ config.setThreadModel(ReadWriteThreadModel.getInstance());
+ }
+
+ synchronized (_inVmPipeAddress)
+ {
+ if (!_inVmPipeAddress.containsKey(port))
+ {
+ _logger.info("Creating InVM Qpid.AMQP listening on port " + port);
+ IoHandlerAdapter provider = null;
+ try
+ {
+ VmPipeAddress pipe = new VmPipeAddress(port);
+
+ provider = createBrokerInstance(port);
+
+ _acceptor.bind(pipe, provider);
+
+ _inVmPipeAddress.put(port, pipe);
+ _logger.info("Created InVM Qpid.AMQP listening on port " + port);
+ }
+ catch (IOException e)
+ {
+ _logger.error("Got IOException.", e);
+
+ // Try and unbind provider
+ try
+ {
+ VmPipeAddress pipe = new VmPipeAddress(port);
+
+ try
+ {
+ _acceptor.unbind(pipe);
+ }
+ catch (Exception ignore)
+ {
+ // ignore
+ }
+
+ if (provider == null)
+ {
+ provider = createBrokerInstance(port);
+ }
+
+ _acceptor.bind(pipe, provider);
+ _inVmPipeAddress.put(port, pipe);
+ _logger.info("Created InVM Qpid.AMQP listening on port " + port);
+ }
+ catch (IOException justUseFirstException)
+ {
+ String because;
+ if (e.getCause() == null)
+ {
+ because = e.toString();
+ }
+ else
+ {
+ because = e.getCause().toString();
+ }
+
+ throw new AMQVMBrokerCreationException(null, port, because + " Stopped binding of InVM Qpid.AMQP", e);
+ }
+ }
+ }
+ else
+ {
+ _logger.info("InVM Qpid.AMQP on port " + port + " already exits.");
+ }
+ }
+ }
+
+ private static IoHandlerAdapter createBrokerInstance(int port) throws AMQVMBrokerCreationException
+ {
+ String protocolProviderClass = System.getProperty("amqj.protocolprovider.class", DEFAULT_QPID_SERVER);
+ _logger.info("Creating Qpid protocol provider: " + protocolProviderClass);
+
+ // can't use introspection to get Provider as it is a server class.
+ // need to go straight to IoHandlerAdapter but that requries the queues and exchange from the ApplicationRegistry which we can't access.
+
+ // get right constructor and pass in instancec ID - "port"
+ IoHandlerAdapter provider;
+ try
+ {
+ Class[] cnstr = { Integer.class };
+ Object[] params = { port };
+ provider = (IoHandlerAdapter) Class.forName(protocolProviderClass).getConstructor(cnstr).newInstance(params);
+ // Give the broker a second to create
+ _logger.info("Created VMBroker Instance:" + port);
+ }
+ catch (Exception e)
+ {
+ _logger.info("Unable to create InVM Qpid.AMQP on port " + port + ". Because: " + e.getCause());
+ String because;
+ if (e.getCause() == null)
+ {
+ because = e.toString();
+ }
+ else
+ {
+ because = e.getCause().toString();
+ }
+
+ AMQVMBrokerCreationException amqbce =
+ new AMQVMBrokerCreationException(null, port, because + " Stopped InVM Qpid.AMQP creation", null);
+ amqbce.initCause(e);
+ throw amqbce;
+ }
+
+ return provider;
+ }
+
+ public static void killAllVMBrokers()
+ {
+ _logger.info("Killing all VM Brokers");
+ _acceptor.unbindAll();
+ synchronized (_inVmPipeAddress)
+ {
+ Iterator keys = _inVmPipeAddress.keySet().iterator();
+
+ while (keys.hasNext())
+ {
+ int id = (Integer) keys.next();
+ _inVmPipeAddress.remove(id);
+ }
+ }
+ }
+
+ public static void killVMBroker(int port)
+ {
+ synchronized (_inVmPipeAddress)
+ {
+ VmPipeAddress pipe = (VmPipeAddress) _inVmPipeAddress.get(port);
+ if (pipe != null)
+ {
+ _logger.info("Killing VM Broker:" + port);
+ _inVmPipeAddress.remove(port);
+ _acceptor.unbind(pipe);
+ }
+ }
+ }
+
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/client/transport/VmPipeTransportConnection.java b/Final/java/client/src/main/java/org/apache/qpid/client/transport/VmPipeTransportConnection.java
new file mode 100644
index 0000000000..d9137dc8b1
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/transport/VmPipeTransportConnection.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.client.transport;
+
+import org.apache.mina.common.ConnectFuture;
+import org.apache.mina.common.IoServiceConfig;
+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.PoolingFilter;
+import org.apache.qpid.pool.ReferenceCountingExecutorService;
+import org.apache.qpid.pool.ReadWriteThreadModel;
+
+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;
+
+ public VmPipeTransportConnection(int port)
+ {
+ _port = port;
+ }
+
+ public void connect(AMQProtocolHandler protocolHandler, BrokerDetails brokerDetail) throws IOException
+ {
+ final VmPipeConnector ioConnector = new VmPipeConnector();
+ 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);
+ // wait for connection to complete
+ future.join();
+ // we call getSession which throws an IOException if there has been an error connecting
+ future.getSession();
+ }
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/client/util/FlowControllingBlockingQueue.java b/Final/java/client/src/main/java/org/apache/qpid/client/util/FlowControllingBlockingQueue.java
new file mode 100644
index 0000000000..579b0d9e90
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/util/FlowControllingBlockingQueue.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.client.util;
+
+import java.util.Iterator;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 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
+ * caller is not obliged to react to the events. <p/> This implementation is <b>only</b> safe where we have a single
+ * thread adding items and a single (different) thread removing items.
+ *
+ * @todo Make this implement java.util.Queue and hide the implementation. Then different queue types can be substituted.
+ */
+public class FlowControllingBlockingQueue
+{
+ /** This queue is bounded and is used to store messages before being dispatched to the consumer */
+ private final BlockingQueue _queue = new LinkedBlockingQueue();
+
+ private final int _flowControlHighThreshold;
+ private final int _flowControlLowThreshold;
+
+ private final ThresholdListener _listener;
+
+ /** We require a separate count so we can track whether we have reached the threshold */
+ private int _count;
+
+ public boolean isEmpty()
+ {
+ return _queue.isEmpty();
+ }
+
+ public interface ThresholdListener
+ {
+ void aboveThreshold(int currentValue);
+
+ void underThreshold(int currentValue);
+ }
+
+ public FlowControllingBlockingQueue(int threshold, ThresholdListener listener)
+ {
+ this(threshold, threshold, listener);
+ }
+
+ public FlowControllingBlockingQueue(int highThreshold, int lowThreshold, ThresholdListener listener)
+ {
+ _flowControlHighThreshold = highThreshold;
+ _flowControlLowThreshold = lowThreshold;
+ _listener = listener;
+ }
+
+ public Object poll(long time, TimeUnit unit) throws InterruptedException
+ {
+ Object o = _queue.poll(time, unit);
+ if (o != null && _listener != null)
+ {
+ synchronized (_listener)
+ {
+ if (_count-- == _flowControlLowThreshold)
+ {
+ _listener.underThreshold(_count);
+ }
+ }
+ }
+
+ return o;
+ }
+
+ public void add(Object o)
+ {
+ _queue.add(o);
+ if (_listener != null)
+ {
+ synchronized (_listener)
+ {
+ if (++_count == _flowControlHighThreshold)
+ {
+ _listener.aboveThreshold(_count);
+ }
+ }
+ }
+ }
+
+ public Iterator iterator()
+ {
+ return _queue.iterator();
+ }
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/client/vmbroker/AMQVMBrokerCreationException.java b/Final/java/client/src/main/java/org/apache/qpid/client/vmbroker/AMQVMBrokerCreationException.java
new file mode 100644
index 0000000000..1791e7ede3
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/client/vmbroker/AMQVMBrokerCreationException.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.client.vmbroker;
+
+import org.apache.qpid.client.transport.AMQTransportConnectionException;
+import org.apache.qpid.protocol.AMQConstant;
+
+/**
+ * AMQVMBrokerCreationException represents failure to create an in VM broker on the vm transport medium.
+ *
+ * <p/><table id="crc"><caption>CRC Card</caption>
+ * <tr><th> Responsibilities <th> Collaborations
+ * <tr><td> Represent failure to create an in VM broker.
+ * </table>
+ */
+public class AMQVMBrokerCreationException extends AMQTransportConnectionException
+{
+ private int _port;
+
+ /**
+ * @param port
+ *
+ * @deprecated
+ */
+ public AMQVMBrokerCreationException(int port)
+ {
+ this(null, port, "Unable to create vm broker", null);
+ }
+
+ public AMQVMBrokerCreationException(AMQConstant errorCode, int port, String message, Throwable cause)
+ {
+ super(errorCode, message, cause);
+ _port = port;
+ }
+
+ public String toString()
+ {
+ return super.toString() + " on port " + _port;
+ }
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/jms/BrokerDetails.java b/Final/java/client/src/main/java/org/apache/qpid/jms/BrokerDetails.java
new file mode 100644
index 0000000000..91f7710025
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/jms/BrokerDetails.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.jms;
+
+import org.apache.qpid.client.SSLConfiguration;
+
+public interface BrokerDetails
+{
+
+ /*
+ * Known URL Options
+ * @see ConnectionURL
+ */
+ public static final String OPTIONS_RETRY = "retries";
+ public static final String OPTIONS_CONNECT_TIMEOUT = "connecttimeout";
+ public static final int DEFAULT_PORT = 5672;
+
+ public static final String TCP = "tcp";
+ public static final String VM = "vm";
+
+ public static final String DEFAULT_TRANSPORT = TCP;
+
+ public static final String URL_FORMAT_EXAMPLE =
+ "<transport>://<hostname>[:<port Default=\"" + DEFAULT_PORT + "\">][?<option>='<value>'[,<option>='<value>']]";
+
+ public static final long DEFAULT_CONNECT_TIMEOUT = 30000L;
+ public static final boolean USE_SSL_DEFAULT = false;
+
+ String getHost();
+
+ void setHost(String host);
+
+ int getPort();
+
+ void setPort(int port);
+
+ String getTransport();
+
+ void setTransport(String transport);
+
+ String getOption(String key);
+
+ void setOption(String key, String value);
+
+ long getTimeout();
+
+ void setTimeout(long timeout);
+
+ SSLConfiguration getSSLConfiguration();
+
+ void setSSLConfiguration(SSLConfiguration sslConfiguration);
+
+ String toString();
+
+ boolean equals(Object o);
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/jms/ChannelLimitReachedException.java b/Final/java/client/src/main/java/org/apache/qpid/jms/ChannelLimitReachedException.java
new file mode 100644
index 0000000000..3d4a4573ed
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/jms/ChannelLimitReachedException.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.jms;
+
+import javax.jms.ResourceAllocationException;
+
+/**
+ * Indicates that the maximum number of sessions per connection limit has been reached.
+ */
+public class ChannelLimitReachedException extends ResourceAllocationException
+{
+ private static final String ERROR_CODE = "1";
+
+ private long _limit;
+
+ public ChannelLimitReachedException(long limit)
+ {
+ super("Unable to create session since maximum number of sessions per connection is " +
+ limit + ". Either close one or more sessions or increase the " +
+ "maximum number of sessions per connection (or contact your AMQP administrator.", ERROR_CODE);
+ _limit = limit;
+ }
+
+ public long getLimit()
+ {
+ return _limit;
+ }
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/jms/Connection.java b/Final/java/client/src/main/java/org/apache/qpid/jms/Connection.java
new file mode 100644
index 0000000000..616c6dbbec
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/jms/Connection.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.jms;
+
+import javax.jms.JMSException;
+
+public interface Connection extends javax.jms.Connection
+{
+ /**
+ * @return the maximum number of sessions supported by this Connection
+ */
+ long getMaximumChannelCount() throws JMSException;
+
+ void setConnectionListener(ConnectionListener listener);
+
+ /**
+ * Get the connection listener that has been registered with this connection, if any
+ *
+ * @return the listener or null if none has been set
+ */
+ ConnectionListener getConnectionListener();
+
+ /**
+ * Create a session specifying the prefetch limit of messages.
+ *
+ * @param transacted
+ * @param acknowledgeMode
+ * @param prefetch the maximum number of messages to buffer in the client. This
+ * applies as a total across all consumers
+ * @return
+ * @throws JMSException
+ */
+ org.apache.qpid.jms.Session createSession(boolean transacted, int acknowledgeMode,
+ int prefetch) throws JMSException;
+
+
+ /**
+ * Create a session specifying the prefetch limit of messages.
+ *
+ * @param transacted
+ * @param acknowledgeMode
+ * @param prefetchHigh the maximum number of messages to buffer in the client.
+ * This applies as a total across all consumers
+ * @param prefetchLow the number of messages that must be in the buffer in the client to renable message flow.
+ * This applies as a total across all consumers
+ * @return
+ * @throws JMSException
+ */
+ org.apache.qpid.jms.Session createSession(boolean transacted, int acknowledgeMode,
+ int prefetchHigh, int prefetchLow) throws JMSException;
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/jms/ConnectionListener.java b/Final/java/client/src/main/java/org/apache/qpid/jms/ConnectionListener.java
new file mode 100644
index 0000000000..11c235901c
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/jms/ConnectionListener.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.jms;
+
+public interface ConnectionListener
+{
+ /**
+ * Called when bytes have been transmitted to the server
+ * @param count the number of bytes sent in total since the connection was opened
+ */
+ void bytesSent(long count);
+
+ /**
+ * Called when some bytes have been received on a connection
+ * @param count the number of bytes received in total since the connection was opened
+ */
+ void bytesReceived(long count);
+
+ /**
+ * Called after the infrastructure has detected that failover is required but before attempting failover.
+ * @param redirect true if the broker requested redirect. false if failover is occurring due to a connection error.
+ * @return true to continue failing over, false to veto failover and raise a connection exception
+ */
+ boolean preFailover(boolean redirect);
+
+ /**
+ * Called after connection has been made to another broker after failover has been started but before
+ * any resubscription has been done.
+ * @return true to continue with resubscription, false to prevent automatic resubscription. This is useful in
+ * cases where the application wants to handle resubscription. Note that in the latter case all sessions, producers
+ * and consumers are invalidated.
+ */
+ boolean preResubscribe();
+
+ /**
+ * Called once failover has completed successfully. This is called irrespective of whether the client has
+ * vetoed automatic resubscription.
+ */
+ void failoverComplete();
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/jms/ConnectionURL.java b/Final/java/client/src/main/java/org/apache/qpid/jms/ConnectionURL.java
new file mode 100644
index 0000000000..2d91e290c4
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/jms/ConnectionURL.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.jms;
+
+import org.apache.qpid.framing.AMQShortString;
+
+import java.util.List;
+
+/**
+ Connection URL format
+ amqp://[user:pass@][clientid]/virtualhost?brokerlist='tcp://host:port?option=\'value\'&option=\'value\';vm://:3/virtualpath?option=\'value\''&failover='method?option=\'value\'&option='value''"
+ Options are of course optional except for requiring a single broker in the broker list.
+ The option seperator is defined to be either '&' or ','
+ */
+public interface ConnectionURL
+{
+ public static final String AMQ_PROTOCOL = "amqp";
+ public static final String OPTIONS_BROKERLIST = "brokerlist";
+ public static final String OPTIONS_FAILOVER = "failover";
+ public static final String OPTIONS_FAILOVER_CYCLE = "cyclecount";
+ public static final String OPTIONS_SSL = "ssl";
+ public static final String OPTIONS_DEFAULT_TOPIC_EXCHANGE = "defaultTopicExchange";
+ public static final String OPTIONS_DEFAULT_QUEUE_EXCHANGE = "defaultQueueExchange";
+ public static final String OPTIONS_TEMPORARY_TOPIC_EXCHANGE = "temporaryTopicExchange";
+ public static final String OPTIONS_TEMPORARY_QUEUE_EXCHANGE = "temporaryQueueExchange";
+
+ String getURL();
+
+ String getFailoverMethod();
+
+ String getFailoverOption(String key);
+
+ int getBrokerCount();
+
+ BrokerDetails getBrokerDetails(int index);
+
+ void addBrokerDetails(BrokerDetails broker);
+
+ List<BrokerDetails> getAllBrokerDetails();
+
+ String getClientName();
+
+ void setClientName(String clientName);
+
+ String getUsername();
+
+ void setUsername(String username);
+
+ String getPassword();
+
+ void setPassword(String password);
+
+ String getVirtualHost();
+
+ void setVirtualHost(String virtualHost);
+
+ String getOption(String key);
+
+ void setOption(String key, String value);
+
+ AMQShortString getDefaultQueueExchangeName();
+
+ AMQShortString getDefaultTopicExchangeName();
+
+ AMQShortString getTemporaryQueueExchangeName();
+
+ AMQShortString getTemporaryTopicExchangeName();
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/jms/FailoverPolicy.java b/Final/java/client/src/main/java/org/apache/qpid/jms/FailoverPolicy.java
new file mode 100644
index 0000000000..6ec883ff0b
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/jms/FailoverPolicy.java
@@ -0,0 +1,324 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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;
+
+import org.apache.qpid.jms.failover.FailoverMethod;
+import org.apache.qpid.jms.failover.FailoverRoundRobinServers;
+import org.apache.qpid.jms.failover.FailoverSingleServer;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class FailoverPolicy
+{
+ private static final Logger _logger = LoggerFactory.getLogger(FailoverPolicy.class);
+
+ private static final long MINUTE = 60000L;
+
+ private static final long DEFAULT_METHOD_TIMEOUT = 1 * MINUTE;
+ private static final long DEFAULT_FAILOVER_TIMEOUT = 4 * MINUTE;
+
+ private FailoverMethod[] _methods = new FailoverMethod[1];
+
+ private int _currentMethod;
+
+ private int _methodsRetries;
+
+ private int _currentRetry;
+
+ private boolean _timing;
+
+ private long _lastMethodTime;
+ private long _lastFailTime;
+
+ public FailoverPolicy(ConnectionURL connectionDetails)
+ {
+ FailoverMethod method;
+
+ // todo This should be integrated in to the connection url when it supports
+ // multiple strategies.
+
+ _methodsRetries = 0;
+
+ if (connectionDetails.getFailoverMethod() == null)
+ {
+ if (connectionDetails.getBrokerCount() > 1)
+ {
+ method = new FailoverRoundRobinServers(connectionDetails);
+ }
+ else
+ {
+ method = new FailoverSingleServer(connectionDetails);
+ }
+ }
+ else
+ {
+ String failoverMethod = connectionDetails.getFailoverMethod();
+
+ /*
+ if (failoverMethod.equals(FailoverMethod.RANDOM))
+ {
+ //todo write a random connection Failover
+ }
+ */
+ if (failoverMethod.equals(FailoverMethod.SINGLE_BROKER))
+ {
+ method = new FailoverRoundRobinServers(connectionDetails);
+ }
+ else
+ {
+ if (failoverMethod.equals(FailoverMethod.ROUND_ROBIN))
+ {
+ method = new FailoverRoundRobinServers(connectionDetails);
+ }
+ else
+ {
+ try
+ {
+ Class[] constructorSpec = { ConnectionURL.class };
+ Object[] params = { connectionDetails };
+
+ method =
+ (FailoverMethod) ClassLoader.getSystemClassLoader().loadClass(failoverMethod)
+ .getConstructor(constructorSpec).newInstance(params);
+ }
+ catch (Exception cnfe)
+ {
+ throw new IllegalArgumentException("Unknown failover method:" + failoverMethod, cnfe);
+ }
+ }
+ }
+ }
+
+ if (method == null)
+ {
+ throw new IllegalArgumentException("Unknown failover method specified.");
+ }
+
+ reset();
+
+ _methods[_currentMethod] = method;
+ }
+
+ public FailoverPolicy(FailoverMethod method)
+ {
+ this(method, 0);
+ }
+
+ public FailoverPolicy(FailoverMethod method, int retries)
+ {
+ _methodsRetries = retries;
+
+ reset();
+
+ _methods[_currentMethod] = method;
+ }
+
+ private void reset()
+ {
+ _currentMethod = 0;
+ _currentRetry = 0;
+ _timing = false;
+
+ }
+
+ public boolean failoverAllowed()
+ {
+ boolean failoverAllowed;
+
+ if (_timing)
+ {
+ long now = System.currentTimeMillis();
+
+ if ((now - _lastMethodTime) >= DEFAULT_METHOD_TIMEOUT)
+ {
+ _logger.info("Failover method timeout");
+ _lastMethodTime = now;
+
+ if (!nextMethod())
+ {
+ return false;
+ }
+
+ }
+ else
+ {
+ if ((now - _lastFailTime) >= DEFAULT_FAILOVER_TIMEOUT)
+ {
+ _logger.info("Failover timeout");
+
+ return false;
+ }
+ else
+ {
+ _lastMethodTime = now;
+ }
+ }
+ }
+ else
+ {
+ _timing = true;
+ _lastMethodTime = System.currentTimeMillis();
+ _lastFailTime = _lastMethodTime;
+ }
+
+ if (_methods[_currentMethod].failoverAllowed())
+ {
+ failoverAllowed = true;
+ }
+ else
+ {
+ if (_currentMethod < (_methods.length - 1))
+ {
+ nextMethod();
+ _logger.info("Changing method to " + _methods[_currentMethod].methodName());
+
+ return failoverAllowed();
+ }
+ else
+ {
+ return cycleMethods();
+ }
+ }
+
+ return failoverAllowed;
+ }
+
+ private boolean nextMethod()
+ {
+ if (_currentMethod < (_methods.length - 1))
+ {
+ _currentMethod++;
+ _methods[_currentMethod].reset();
+
+ return true;
+ }
+ else
+ {
+ return cycleMethods();
+ }
+ }
+
+ private boolean cycleMethods()
+ {
+ if (_currentRetry < _methodsRetries)
+ {
+ _currentRetry++;
+
+ _currentMethod = 0;
+
+ _logger.info("Retrying methods starting with " + _methods[_currentMethod].methodName());
+ _methods[_currentMethod].reset();
+
+ return failoverAllowed();
+ }
+ else
+ {
+ _logger.debug("All failover methods exhausted");
+
+ return false;
+ }
+ }
+
+ /**
+ * Notification that connection was successful.
+ */
+ public void attainedConnection()
+ {
+ _currentRetry = 0;
+
+ _methods[_currentMethod].attainedConnection();
+
+ _timing = false;
+ }
+
+ public BrokerDetails getCurrentBrokerDetails()
+ {
+ return _methods[_currentMethod].getCurrentBrokerDetails();
+ }
+
+ public BrokerDetails getNextBrokerDetails()
+ {
+ return _methods[_currentMethod].getNextBrokerDetails();
+ }
+
+ public void setBroker(BrokerDetails broker)
+ {
+ _methods[_currentMethod].setBroker(broker);
+ }
+
+ public void addMethod(FailoverMethod method)
+ {
+ int len = _methods.length + 1;
+ FailoverMethod[] newMethods = new FailoverMethod[len];
+ System.arraycopy(_methods, 0, newMethods, 0, _methods.length);
+ int index = len - 1;
+ newMethods[index] = method;
+ _methods = newMethods;
+ }
+
+ public void setMethodRetries(int retries)
+ {
+ _methodsRetries = retries;
+ }
+
+ public FailoverMethod getCurrentMethod()
+ {
+ if ((_currentMethod >= 0) && (_currentMethod < (_methods.length - 1)))
+ {
+ return _methods[_currentMethod];
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ public String toString()
+ {
+ StringBuffer sb = new StringBuffer();
+
+ sb.append("Failover Policy:\n");
+
+ if (failoverAllowed())
+ {
+ sb.append("Failover allowed\n");
+ }
+ else
+ {
+ sb.append("Failover not allowed\n");
+ }
+
+ sb.append("Failover policy methods\n");
+ for (int i = 0; i < _methods.length; i++)
+ {
+
+ if (i == _currentMethod)
+ {
+ sb.append(">");
+ }
+
+ sb.append(_methods[i].toString());
+ }
+
+ return sb.toString();
+ }
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/jms/Message.java b/Final/java/client/src/main/java/org/apache/qpid/jms/Message.java
new file mode 100644
index 0000000000..6752ee616f
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/jms/Message.java
@@ -0,0 +1,28 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.jms;
+
+import javax.jms.JMSException;
+
+public interface Message extends javax.jms.Message
+{
+ public void acknowledgeThis() throws JMSException;
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/jms/MessageConsumer.java b/Final/java/client/src/main/java/org/apache/qpid/jms/MessageConsumer.java
new file mode 100644
index 0000000000..caac2b5c1f
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/jms/MessageConsumer.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.jms;
+
+/**
+ */
+public interface MessageConsumer extends javax.jms.MessageConsumer
+{
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/jms/MessageProducer.java b/Final/java/client/src/main/java/org/apache/qpid/jms/MessageProducer.java
new file mode 100644
index 0000000000..b91fc2d960
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/jms/MessageProducer.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.jms;
+
+import java.io.UnsupportedEncodingException;
+
+import javax.jms.Destination;
+import javax.jms.JMSException;
+import javax.jms.Message;
+
+/**
+ */
+public interface MessageProducer extends javax.jms.MessageProducer
+{
+ /**
+ * Set the default MIME type for messages produced by this producer. This reduces the overhead of each message.
+ * @param mimeType
+ */
+ void setMimeType(String mimeType) throws JMSException;
+
+ /**
+ * Set the default encoding for messages produced by this producer. This reduces the overhead of each message.
+ * @param encoding the encoding as understood by XXXX how do I specify this?? RG
+ * @throws UnsupportedEncodingException if the encoding is not understood
+ */
+ void setEncoding(String encoding) throws UnsupportedEncodingException, JMSException;
+
+ void send(Destination destination, Message message, int deliveryMode,
+ int priority, long timeToLive, boolean immediate)
+ throws JMSException;
+
+ void send(Destination destination, Message message, int deliveryMode,
+ int priority, long timeToLive, boolean mandatory, boolean immediate)
+ throws JMSException;
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/jms/Session.java b/Final/java/client/src/main/java/org/apache/qpid/jms/Session.java
new file mode 100644
index 0000000000..5287381fae
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/jms/Session.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.jms;
+
+import org.apache.qpid.framing.AMQShortString;
+
+import javax.jms.Destination;
+import javax.jms.JMSException;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageProducer;
+
+
+public interface Session extends javax.jms.Session
+{
+ /**
+ * Indicates that no client acknowledgements are required. Broker assumes that once it has delivered
+ * a message packet successfully it is acknowledged.
+ */
+ static final int NO_ACKNOWLEDGE = 257;
+
+ /**
+ * Pre acknowledge means that an ack is sent per message but sent before user code has processed
+ * the message (i.e. before the onMessage() call or the receive() method has returned).
+ */
+ static final int PRE_ACKNOWLEDGE = 258;
+
+ MessageConsumer createConsumer(Destination destination,
+ int prefetch,
+ boolean noLocal,
+ boolean exclusive,
+ String selector) throws JMSException;
+
+ MessageConsumer createConsumer(Destination destination,
+ int prefetchHigh,
+ int prefetchLow,
+ boolean noLocal,
+ boolean exclusive,
+ String selector) throws JMSException;
+
+ /**
+ * @return the prefetch value used by default for consumers created on this session.
+ */
+ int getDefaultPrefetch();
+
+ /**
+ * @return the High water prefetch value used by default for consumers created on this session.
+ */
+ int getDefaultPrefetchHigh();
+
+ /**
+ * @return the Low water prefetch value used by default for consumers created on this session.
+ */
+ int getDefaultPrefetchLow();
+
+ /**
+ * Create a producer
+ * @param destination
+ * @param mandatory the value of the mandatory flag used by default on the producer
+ * @param immediate the value of the immediate flag used by default on the producer
+ * @return
+ * @throws JMSException
+ */
+ MessageProducer createProducer(Destination destination, boolean mandatory, boolean immediate)
+ throws JMSException;
+
+ /**
+ * Create a producer
+ * @param destination
+ * @param immediate the value of the immediate flag used by default on the producer
+ * @return
+ * @throws JMSException
+ */
+ MessageProducer createProducer(Destination destination, boolean immediate)
+ throws JMSException;
+
+ AMQShortString getTemporaryTopicExchangeName();
+
+ AMQShortString getDefaultQueueExchangeName();
+
+ AMQShortString getDefaultTopicExchangeName();
+
+ AMQShortString getTemporaryQueueExchangeName();
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/jms/failover/FailoverMethod.java b/Final/java/client/src/main/java/org/apache/qpid/jms/failover/FailoverMethod.java
new file mode 100644
index 0000000000..d7ec46dea3
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/jms/failover/FailoverMethod.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.jms.failover;
+
+import org.apache.qpid.jms.BrokerDetails;
+
+public interface FailoverMethod
+{
+ public static final String SINGLE_BROKER = "singlebroker";
+ public static final String ROUND_ROBIN = "roundrobin";
+ public static final String RANDOM = "random";
+ /**
+ * Reset the Failover to initial conditions
+ */
+ void reset();
+
+ /**
+ * Check if failover is possible for this method
+ *
+ * @return true if failover is allowed
+ */
+ boolean failoverAllowed();
+
+ /**
+ * Notification to the Failover method that a connection has been attained.
+ */
+ void attainedConnection();
+
+ /**
+ * If there is no current BrokerDetails the null will be returned.
+ * @return The current BrokerDetail value to use
+ */
+ BrokerDetails getCurrentBrokerDetails();
+
+ /**
+ * Move to the next BrokerDetails if one is available.
+ * @return the next BrokerDetail or null if there is none.
+ */
+ BrokerDetails getNextBrokerDetails();
+
+ /**
+ * Set the currently active broker to be the new value.
+ * @param broker The new BrokerDetail value
+ */
+ void setBroker(BrokerDetails broker);
+
+ /**
+ * Set the retries for this method
+ * @param maxRetries the maximum number of time to retry this Method
+ */
+ void setRetries(int maxRetries);
+
+ /**
+ * @return The name of this method for display purposes.
+ */
+ String methodName();
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/jms/failover/FailoverRoundRobinServers.java b/Final/java/client/src/main/java/org/apache/qpid/jms/failover/FailoverRoundRobinServers.java
new file mode 100644
index 0000000000..4e0d0b79b5
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/jms/failover/FailoverRoundRobinServers.java
@@ -0,0 +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.
+ *
+ */
+package org.apache.qpid.jms.failover;
+
+import org.apache.qpid.jms.BrokerDetails;
+import org.apache.qpid.jms.ConnectionURL;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+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;
+ /** 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;
+
+ /**
+ * The number of times to retry connecting for each server
+ */
+ private int _serverRetries;
+
+ /**
+ * The current number of retry attempts made
+ */
+ private int _currentServerRetry;
+
+ /**
+ * The number of times to cycle through the servers
+ */
+ private int _cycleRetries;
+
+ /**
+ * The current number of cycles performed.
+ */
+ private int _currentCycleRetries;
+
+ /**
+ * Array of BrokerDetail used to make connections.
+ */
+ private ConnectionURL _connectionDetails;
+
+ public FailoverRoundRobinServers(ConnectionURL connectionDetails)
+ {
+ if (!(connectionDetails.getBrokerCount() > 0))
+ {
+ throw new IllegalArgumentException("At least one broker details must be specified.");
+ }
+
+ _connectionDetails = connectionDetails;
+
+ // There is no current broker at startup so set it to -1.
+ _currentBrokerIndex = -1;
+
+ String cycleRetries = _connectionDetails.getFailoverOption(ConnectionURL.OPTIONS_FAILOVER_CYCLE);
+
+ if (cycleRetries != null)
+ {
+ try
+ {
+ _cycleRetries = Integer.parseInt(cycleRetries);
+ }
+ catch (NumberFormatException nfe)
+ {
+ _cycleRetries = DEFAULT_CYCLE_RETRIES;
+ }
+ }
+
+ _currentCycleRetries = 0;
+
+ _serverRetries = 0;
+ _currentServerRetry = -1;
+ }
+
+ public void reset()
+ {
+ _currentBrokerIndex = 0;
+ _currentCycleRetries = 0;
+ _currentServerRetry = -1;
+ }
+
+ public boolean failoverAllowed()
+ {
+ return ((_currentCycleRetries < _cycleRetries) || (_currentServerRetry < _serverRetries)
+ || (_currentBrokerIndex < (_connectionDetails.getBrokerCount() - 1)));
+ }
+
+ public void attainedConnection()
+ {
+ _currentCycleRetries = 0;
+ _currentServerRetry = -1;
+ }
+
+ public BrokerDetails getCurrentBrokerDetails()
+ {
+ if (_currentBrokerIndex == -1)
+ {
+ return null;
+ }
+
+ return _connectionDetails.getBrokerDetails(_currentBrokerIndex);
+ }
+
+ public BrokerDetails getNextBrokerDetails()
+ {
+ if (_currentBrokerIndex == (_connectionDetails.getBrokerCount() - 1))
+ {
+ 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));
+ }
+
+ _currentServerRetry++;
+ }
+ else
+ {
+ _currentCycleRetries++;
+ // failed to connect to first broker
+ _currentBrokerIndex = 0;
+
+ setBroker(_connectionDetails.getBrokerDetails(_currentBrokerIndex));
+
+ // This is zero rather than -1 as we are already retrieving the details.
+ _currentServerRetry = 0;
+ }
+ // else - should force client to stop as max retries has been reached.
+ }
+ else
+ {
+ 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));
+ }
+
+ _currentServerRetry++;
+ }
+ else
+ {
+ _currentBrokerIndex++;
+
+ setBroker(_connectionDetails.getBrokerDetails(_currentBrokerIndex));
+ // This is zero rather than -1 as we are already retrieving the details.
+ _currentServerRetry = 0;
+ }
+ }
+
+ return _connectionDetails.getBrokerDetails(_currentBrokerIndex);
+ }
+
+ public void setBroker(BrokerDetails broker)
+ {
+
+ _connectionDetails.addBrokerDetails(broker);
+
+ int index = _connectionDetails.getAllBrokerDetails().indexOf(broker);
+
+ String serverRetries = broker.getOption(BrokerDetails.OPTIONS_RETRY);
+
+ if (serverRetries != null)
+ {
+ try
+ {
+ _serverRetries = Integer.parseInt(serverRetries);
+ }
+ catch (NumberFormatException nfe)
+ {
+ _serverRetries = DEFAULT_SERVER_RETRIES;
+ }
+ }
+
+ _currentServerRetry = -1;
+ _currentBrokerIndex = index;
+ }
+
+ public void setRetries(int maxRetries)
+ {
+ _cycleRetries = maxRetries;
+ }
+
+ public String methodName()
+ {
+ return "Cycle Servers";
+ }
+
+ public String toString()
+ {
+ StringBuffer sb = new StringBuffer();
+
+ sb.append("Cycle Servers:\n");
+
+ sb.append("Cycle Retries:");
+ sb.append(_cycleRetries);
+ sb.append("\nCurrent Cycle:");
+ sb.append(_currentCycleRetries);
+ sb.append("\nServer Retries:");
+ sb.append(_serverRetries);
+ sb.append("\nCurrent Retry:");
+ sb.append(_currentServerRetry);
+ sb.append("\nCurrent Broker:");
+ sb.append(_currentBrokerIndex);
+ sb.append("\n");
+
+ for (int i = 0; i < _connectionDetails.getBrokerCount(); i++)
+ {
+ if (i == _currentBrokerIndex)
+ {
+ sb.append(">");
+ }
+
+ sb.append(_connectionDetails.getBrokerDetails(i));
+ sb.append("\n");
+ }
+
+ return sb.toString();
+ }
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/jms/failover/FailoverSingleServer.java b/Final/java/client/src/main/java/org/apache/qpid/jms/failover/FailoverSingleServer.java
new file mode 100644
index 0000000000..68e6d25be0
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/jms/failover/FailoverSingleServer.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.jms.failover;
+
+import org.apache.qpid.jms.BrokerDetails;
+import org.apache.qpid.jms.ConnectionURL;
+
+public class FailoverSingleServer implements FailoverMethod
+{
+ /** The default number of times to rety a conection to this server */
+ public static final int DEFAULT_SERVER_RETRIES = 1;
+
+ /**
+ * The details of the Single Server
+ */
+ private BrokerDetails _brokerDetail;
+
+ /**
+ * The number of times to retry connecting to the sever
+ */
+ private int _retries;
+
+ /**
+ * The current number of attempts made to the server
+ */
+ private int _currentRetries;
+
+
+ public FailoverSingleServer(ConnectionURL connectionDetails)
+ {
+ if (connectionDetails.getBrokerCount() > 0)
+ {
+ setBroker(connectionDetails.getBrokerDetails(0));
+ }
+ else
+ {
+ throw new IllegalArgumentException("BrokerDetails details required for connection.");
+ }
+ }
+
+ public FailoverSingleServer(BrokerDetails brokerDetail)
+ {
+ setBroker(brokerDetail);
+ }
+
+ public void reset()
+ {
+ _currentRetries = -1;
+ }
+
+ public boolean failoverAllowed()
+ {
+ return _currentRetries < _retries;
+ }
+
+ public void attainedConnection()
+ {
+ reset();
+ }
+
+ public BrokerDetails getCurrentBrokerDetails()
+ {
+ return _brokerDetail;
+ }
+
+ public BrokerDetails getNextBrokerDetails()
+ {
+ if (_currentRetries == _retries)
+ {
+ return null;
+ }
+ else
+ {
+ if (_currentRetries < _retries)
+ {
+ _currentRetries ++;
+ }
+
+ return _brokerDetail;
+ }
+ }
+
+ public void setBroker(BrokerDetails broker)
+ {
+ if (broker == null)
+ {
+ throw new IllegalArgumentException("BrokerDetails details cannot be null");
+ }
+ _brokerDetail = broker;
+
+ String retries = broker.getOption(BrokerDetails.OPTIONS_RETRY);
+ if (retries != null)
+ {
+ try
+ {
+ _retries = Integer.parseInt(retries);
+ }
+ catch (NumberFormatException nfe)
+ {
+ _retries = DEFAULT_SERVER_RETRIES;
+ }
+ }
+ else
+ {
+ _retries = DEFAULT_SERVER_RETRIES;
+ }
+
+ reset();
+ }
+
+ public void setRetries(int retries)
+ {
+ _retries = retries;
+ }
+
+ public String methodName()
+ {
+ return "Single Server";
+ }
+
+ public String toString()
+ {
+ return "SingleServer:\n"+
+ "Max Retries:"+_retries+
+ "\nCurrent Retry:"+_currentRetries+
+ "\n"+_brokerDetail+"\n";
+ }
+
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/jndi/Example.properties b/Final/java/client/src/main/java/org/apache/qpid/jndi/Example.properties
new file mode 100644
index 0000000000..c457e94cab
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/jndi/Example.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.
+#
+java.naming.factory.initial = org.apache.qpid.jndi.PropertiesFileInitialConextFactory
+
+# use the following property to configure the default connector
+#java.naming.provider.url - ignored.
+
+# register some connection factories
+# connectionfactory.[jndiname] = [ConnectionURL]
+connectionfactory.local = amqp://guest:guest@clientid/testpath?brokerlist='vm://:1'
+
+# register some queues in JNDI using the form
+# queue.[jndiName] = [physicalName]
+queue.MyQueue = example.MyQueue
+
+# register some topics in JNDI using the form
+# topic.[jndiName] = [physicalName]
+topic.ibmStocks = stocks.nyse.ibm
+
+# Register an AMQP destination in JNDI
+# NOTE: Qpid currently only supports direct,topics and headers
+# destination.[jniName] = [BindingURL]
+destination.direct = direct://amq.direct//directQueue
diff --git a/Final/java/client/src/main/java/org/apache/qpid/jndi/NameParserImpl.java b/Final/java/client/src/main/java/org/apache/qpid/jndi/NameParserImpl.java
new file mode 100644
index 0000000000..a3174aec7a
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/jndi/NameParserImpl.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.jndi;
+
+import javax.naming.CompositeName;
+import javax.naming.Name;
+import javax.naming.NameParser;
+import javax.naming.NamingException;
+
+/**
+ * A default implementation of {@link NameParser}
+ * <p/>
+ * Based on class from ActiveMQ.
+ */
+public class NameParserImpl implements NameParser
+{
+ public Name parse(String name) throws NamingException
+ {
+ return new CompositeName(name);
+ }
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/jndi/PropertiesFileInitialContextFactory.java b/Final/java/client/src/main/java/org/apache/qpid/jndi/PropertiesFileInitialContextFactory.java
new file mode 100644
index 0000000000..a46c7f3cd5
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/jndi/PropertiesFileInitialContextFactory.java
@@ -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.
+ *
+ */
+package org.apache.qpid.jndi;
+
+import org.apache.qpid.client.AMQConnectionFactory;
+import org.apache.qpid.client.AMQDestination;
+import org.apache.qpid.client.AMQHeadersExchange;
+import org.apache.qpid.client.AMQQueue;
+import org.apache.qpid.client.AMQTopic;
+import org.apache.qpid.exchange.ExchangeDefaults;
+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.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.jms.ConnectionFactory;
+import javax.jms.Destination;
+import javax.jms.Queue;
+import javax.jms.Topic;
+import javax.naming.Context;
+import javax.naming.NamingException;
+import javax.naming.spi.InitialContextFactory;
+
+import java.io.BufferedInputStream;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Properties;
+import java.util.concurrent.ConcurrentHashMap;
+
+public class PropertiesFileInitialContextFactory implements InitialContextFactory
+{
+ protected final Logger _logger = LoggerFactory.getLogger(PropertiesFileInitialContextFactory.class);
+
+ private String CONNECTION_FACTORY_PREFIX = "connectionfactory.";
+ private String DESTINATION_PREFIX = "destination.";
+ private String QUEUE_PREFIX = "queue.";
+ private String TOPIC_PREFIX = "topic.";
+
+ public Context getInitialContext(Hashtable environment) throws NamingException
+ {
+ Map data = new ConcurrentHashMap();
+
+ try
+ {
+
+ String file = null;
+ if (environment.containsKey(Context.PROVIDER_URL))
+ {
+ file = (String) environment.get(Context.PROVIDER_URL);
+ }
+ else
+ {
+ file = System.getProperty(Context.PROVIDER_URL);
+ }
+
+ if (file != null)
+ {
+ _logger.info("Loading Properties from:" + file);
+ // Load the properties specified
+ Properties p = new Properties();
+
+ p.load(new BufferedInputStream(new FileInputStream(file)));
+
+ environment.putAll(p);
+ _logger.info("Loaded Context Properties:" + environment.toString());
+ }
+ else
+ {
+ _logger.info("No Provider URL specified.");
+ }
+ }
+ catch (IOException ioe)
+ {
+ _logger.warn("Unable to load property file specified in Provider_URL:" + environment.get(Context.PROVIDER_URL));
+ }
+
+ createConnectionFactories(data, environment);
+
+ createDestinations(data, environment);
+
+ createQueues(data, environment);
+
+ createTopics(data, environment);
+
+ return createContext(data, environment);
+ }
+
+ // Implementation methods
+ // -------------------------------------------------------------------------
+ protected ReadOnlyContext createContext(Map data, Hashtable environment)
+ {
+ return new ReadOnlyContext(environment, data);
+ }
+
+ protected void createConnectionFactories(Map data, Hashtable environment)
+ {
+ for (Iterator iter = environment.entrySet().iterator(); iter.hasNext();)
+ {
+ Map.Entry entry = (Map.Entry) iter.next();
+ String key = entry.getKey().toString();
+ if (key.startsWith(CONNECTION_FACTORY_PREFIX))
+ {
+ String jndiName = key.substring(CONNECTION_FACTORY_PREFIX.length());
+ ConnectionFactory cf = createFactory(entry.getValue().toString());
+ if (cf != null)
+ {
+ data.put(jndiName, cf);
+ }
+ }
+ }
+ }
+
+ protected void createDestinations(Map data, Hashtable environment)
+ {
+ for (Iterator iter = environment.entrySet().iterator(); iter.hasNext();)
+ {
+ Map.Entry entry = (Map.Entry) iter.next();
+ String key = entry.getKey().toString();
+ if (key.startsWith(DESTINATION_PREFIX))
+ {
+ String jndiName = key.substring(DESTINATION_PREFIX.length());
+ Destination dest = createDestination(entry.getValue().toString());
+ if (dest != null)
+ {
+ data.put(jndiName, dest);
+ }
+ }
+ }
+ }
+
+ protected void createQueues(Map data, Hashtable environment)
+ {
+ for (Iterator iter = environment.entrySet().iterator(); iter.hasNext();)
+ {
+ Map.Entry entry = (Map.Entry) iter.next();
+ String key = entry.getKey().toString();
+ if (key.startsWith(QUEUE_PREFIX))
+ {
+ String jndiName = key.substring(QUEUE_PREFIX.length());
+ Queue q = createQueue(entry.getValue().toString());
+ if (q != null)
+ {
+ data.put(jndiName, q);
+ }
+ }
+ }
+ }
+
+ protected void createTopics(Map data, Hashtable environment)
+ {
+ for (Iterator iter = environment.entrySet().iterator(); iter.hasNext();)
+ {
+ Map.Entry entry = (Map.Entry) iter.next();
+ String key = entry.getKey().toString();
+ if (key.startsWith(TOPIC_PREFIX))
+ {
+ String jndiName = key.substring(TOPIC_PREFIX.length());
+ Topic t = createTopic(entry.getValue().toString());
+ if (t != null)
+ {
+ data.put(jndiName, t);
+ }
+ }
+ }
+ }
+
+ /**
+ * Factory method to create new Connection Factory instances
+ */
+ protected ConnectionFactory createFactory(String url)
+ {
+ try
+ {
+ return new AMQConnectionFactory(url);
+ }
+ catch (URLSyntaxException urlse)
+ {
+ _logger.warn("Unable to createFactories:" + urlse);
+ }
+
+ return null;
+ }
+
+ /**
+ * Factory method to create new Destination instances from an AMQP BindingURL
+ */
+ protected Destination createDestination(String bindingURL)
+ {
+ AMQBindingURL binding;
+ try
+ {
+ binding = new AMQBindingURL(bindingURL);
+ }
+ catch (URLSyntaxException urlse)
+ {
+ _logger.warn("Unable to destination:" + urlse);
+
+ return null;
+ }
+
+ try
+ {
+ return AMQDestination.createDestination(binding);
+ }
+ catch (IllegalArgumentException iaw)
+ {
+ _logger.warn("Binding: '" + binding + "' not supported");
+
+ return null;
+ }
+ }
+
+ /**
+ * Factory method to create new Queue instances
+ */
+ protected Queue createQueue(Object value)
+ {
+ if (value instanceof AMQShortString)
+ {
+ return new AMQQueue(ExchangeDefaults.DIRECT_EXCHANGE_NAME, (AMQShortString) value);
+ }
+ else if (value instanceof String)
+ {
+ return new AMQQueue(ExchangeDefaults.DIRECT_EXCHANGE_NAME, new AMQShortString((String) value));
+ }
+ else if (value instanceof BindingURL)
+ {
+ return new AMQQueue((BindingURL) value);
+ }
+
+ return null;
+ }
+
+ /**
+ * Factory method to create new Topic instances
+ */
+ protected Topic createTopic(Object value)
+ {
+ if (value instanceof AMQShortString)
+ {
+ return new AMQTopic(ExchangeDefaults.TOPIC_EXCHANGE_NAME, (AMQShortString) value);
+ }
+ else if (value instanceof String)
+ {
+ return new AMQTopic(ExchangeDefaults.TOPIC_EXCHANGE_NAME, new AMQShortString((String) value));
+ }
+ else if (value instanceof BindingURL)
+ {
+ return new AMQTopic((BindingURL) value);
+ }
+
+ return null;
+ }
+
+ /**
+ * Factory method to create new HeaderExcahnge instances
+ */
+ protected Destination createHeaderExchange(Object value)
+ {
+ if (value instanceof String)
+ {
+ return new AMQHeadersExchange((String) value);
+ }
+ else if (value instanceof BindingURL)
+ {
+ return new AMQHeadersExchange((BindingURL) value);
+ }
+
+ return null;
+ }
+
+ // Properties
+ // -------------------------------------------------------------------------
+ public String getConnectionPrefix()
+ {
+ return CONNECTION_FACTORY_PREFIX;
+ }
+
+ public void setConnectionPrefix(String connectionPrefix)
+ {
+ this.CONNECTION_FACTORY_PREFIX = connectionPrefix;
+ }
+
+ public String getDestinationPrefix()
+ {
+ return DESTINATION_PREFIX;
+ }
+
+ public void setDestinationPrefix(String destinationPrefix)
+ {
+ this.DESTINATION_PREFIX = destinationPrefix;
+ }
+
+ public String getQueuePrefix()
+ {
+ return QUEUE_PREFIX;
+ }
+
+ public void setQueuePrefix(String queuePrefix)
+ {
+ this.QUEUE_PREFIX = queuePrefix;
+ }
+
+ public String getTopicPrefix()
+ {
+ return TOPIC_PREFIX;
+ }
+
+ public void setTopicPrefix(String topicPrefix)
+ {
+ this.TOPIC_PREFIX = topicPrefix;
+ }
+}
diff --git a/Final/java/client/src/main/java/org/apache/qpid/jndi/ReadOnlyContext.java b/Final/java/client/src/main/java/org/apache/qpid/jndi/ReadOnlyContext.java
new file mode 100644
index 0000000000..1719ea1219
--- /dev/null
+++ b/Final/java/client/src/main/java/org/apache/qpid/jndi/ReadOnlyContext.java
@@ -0,0 +1,527 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.jndi;
+
+import java.io.Serializable;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Map;
+
+import javax.naming.Binding;
+import javax.naming.CompositeName;
+import javax.naming.Context;
+import javax.naming.LinkRef;
+import javax.naming.Name;
+import javax.naming.NameClassPair;
+import javax.naming.NameNotFoundException;
+import javax.naming.NameParser;
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+import javax.naming.NotContextException;
+import javax.naming.OperationNotSupportedException;
+import javax.naming.Reference;
+import javax.naming.spi.NamingManager;
+
+/**
+ * Based on class from ActiveMQ.
+ * A read-only Context
+ * <p/>
+ * This version assumes it and all its subcontext are read-only and any attempt
+ * to modify (e.g. through bind) will result in an OperationNotSupportedException.
+ * Each Context in the tree builds a cache of the entries in all sub-contexts
+ * to optimise the performance of lookup.
+ * </p>
+ * <p>This implementation is intended to optimise the performance of lookup(String)
+ * to about the level of a HashMap get. It has been observed that the scheme
+ * resolution phase performed by the JVM takes considerably longer, so for
+ * optimum performance lookups should be coded like:</p>
+ * <code>
+ * Context componentContext = (Context)new InitialContext().lookup("java:comp");
+ * String envEntry = (String) componentContext.lookup("env/myEntry");
+ * String envEntry2 = (String) componentContext.lookup("env/myEntry2");
+ * </code>
+ */
+public class ReadOnlyContext implements Context, Serializable
+{
+ private static final long serialVersionUID = -5754338187296859149L;
+ protected static final NameParser nameParser = new NameParserImpl();
+
+ protected final Hashtable environment; // environment for this context
+ protected final Map bindings; // bindings at my level
+ protected final Map treeBindings; // all bindings under me
+
+ private boolean frozen = false;
+ private String nameInNamespace = "";
+ public static final String SEPARATOR = "/";
+
+ public ReadOnlyContext()
+ {
+ environment = new Hashtable();
+ bindings = new HashMap();
+ treeBindings = new HashMap();
+ }
+
+ public ReadOnlyContext(Hashtable env)
+ {
+ if (env == null)
+ {
+ this.environment = new Hashtable();
+ }
+ else
+ {
+ this.environment = new Hashtable(env);
+ }
+
+ this.bindings = Collections.EMPTY_MAP;
+ this.treeBindings = Collections.EMPTY_MAP;
+ }
+
+ public ReadOnlyContext(Hashtable environment, Map bindings)
+ {
+ if (environment == null)
+ {
+ this.environment = new Hashtable();
+ }
+ else
+ {
+ this.environment = new Hashtable(environment);
+ }
+
+ this.bindings = bindings;
+ treeBindings = new HashMap();
+ frozen = true;
+ }
+
+ public ReadOnlyContext(Hashtable environment, Map bindings, String nameInNamespace)
+ {
+ this(environment, bindings);
+ this.nameInNamespace = nameInNamespace;
+ }
+
+ protected ReadOnlyContext(ReadOnlyContext clone, Hashtable env)
+ {
+ this.bindings = clone.bindings;
+ this.treeBindings = clone.treeBindings;
+ this.environment = new Hashtable(env);
+ }
+
+ protected ReadOnlyContext(ReadOnlyContext clone, Hashtable env, String nameInNamespace)
+ {
+ this(clone, env);
+ this.nameInNamespace = nameInNamespace;
+ }
+
+ public void freeze()
+ {
+ frozen = true;
+ }
+
+ boolean isFrozen()
+ {
+ return frozen;
+ }
+
+ /**
+ * internalBind is intended for use only during setup or possibly by suitably synchronized superclasses.
+ * It binds every possible lookup into a map in each context. To do this, each context
+ * strips off one name segment and if necessary creates a new context for it. Then it asks that context
+ * to bind the remaining name. It returns a map containing all the bindings from the next context, plus
+ * the context it just created (if it in fact created it). (the names are suitably extended by the segment
+ * originally lopped off).
+ *
+ * @param name
+ * @param value
+ * @return
+ * @throws javax.naming.NamingException
+ */
+ protected Map internalBind(String name, Object value) throws NamingException
+ {
+ assert (name != null) && (name.length() > 0);
+ assert !frozen;
+
+ Map newBindings = new HashMap();
+ int pos = name.indexOf('/');
+ if (pos == -1)
+ {
+ if (treeBindings.put(name, value) != null)
+ {
+ throw new NamingException("Something already bound at " + name);
+ }
+
+ bindings.put(name, value);
+ newBindings.put(name, value);
+ }
+ else
+ {
+ String segment = name.substring(0, pos);
+ assert segment != null;
+ assert !segment.equals("");
+ Object o = treeBindings.get(segment);
+ if (o == null)
+ {
+ o = newContext();
+ treeBindings.put(segment, o);
+ bindings.put(segment, o);
+ newBindings.put(segment, o);
+ }
+ else if (!(o instanceof ReadOnlyContext))
+ {
+ throw new NamingException("Something already bound where a subcontext should go");
+ }
+
+ ReadOnlyContext readOnlyContext = (ReadOnlyContext) o;
+ String remainder = name.substring(pos + 1);
+ Map subBindings = readOnlyContext.internalBind(remainder, value);
+ for (Iterator iterator = subBindings.entrySet().iterator(); iterator.hasNext();)
+ {
+ Map.Entry entry = (Map.Entry) iterator.next();
+ String subName = segment + "/" + (String) entry.getKey();
+ Object bound = entry.getValue();
+ treeBindings.put(subName, bound);
+ newBindings.put(subName, bound);
+ }
+ }
+
+ return newBindings;
+ }
+
+ protected ReadOnlyContext newContext()
+ {
+ return new ReadOnlyContext();
+ }
+
+ public Object addToEnvironment(String propName, Object propVal) throws NamingException
+ {
+ return environment.put(propName, propVal);
+ }
+
+ public Hashtable getEnvironment() throws NamingException
+ {
+ return (Hashtable) environment.clone();
+ }
+
+ public Object removeFromEnvironment(String propName) throws NamingException
+ {
+ return environment.remove(propName);
+ }
+
+ public Object lookup(String name) throws NamingException
+ {
+ if (name.length() == 0)
+ {
+ return this;
+ }
+
+ Object result = treeBindings.get(name);
+ if (result == null)
+ {
+ result = bindings.get(name);
+ }
+
+ if (result == null)
+ {
+ int pos = name.indexOf(':');
+ if (pos > 0)
+ {
+ String scheme = name.substring(0, pos);
+ Context ctx = NamingManager.getURLContext(scheme, environment);
+ if (ctx == null)
+ {
+ throw new NamingException("scheme " + scheme + " not recognized");
+ }
+
+ return ctx.lookup(name);
+ }
+ else
+ {
+ // Split out the first name of the path
+ // and look for it in the bindings map.
+ CompositeName path = new CompositeName(name);
+
+ if (path.size() == 0)
+ {
+ return this;
+ }
+ else
+ {
+ String first = path.get(0);
+ Object obj = bindings.get(first);
+ if (obj == null)
+ {
+ throw new NameNotFoundException(name);
+ }
+ else if ((obj instanceof Context) && (path.size() > 1))
+ {
+ Context subContext = (Context) obj;
+ obj = subContext.lookup(path.getSuffix(1));
+ }
+
+ return obj;
+ }
+ }
+ }
+
+ if (result instanceof LinkRef)
+ {
+ LinkRef ref = (LinkRef) result;
+ result = lookup(ref.getLinkName());
+ }
+
+ if (result instanceof Reference)
+ {
+ try
+ {
+ result = NamingManager.getObjectInstance(result, null, null, this.environment);
+ }
+ catch (NamingException e)
+ {
+ throw e;
+ }
+ catch (Exception e)
+ {
+ throw (NamingException) new NamingException("could not look up : " + name).initCause(e);
+ }
+ }
+
+ if (result instanceof ReadOnlyContext)
+ {
+ String prefix = getNameInNamespace();
+ if (prefix.length() > 0)
+ {
+ prefix = prefix + SEPARATOR;
+ }
+
+ result = new ReadOnlyContext((ReadOnlyContext) result, environment, prefix + name);
+ }
+
+ return result;
+ }
+
+ public Object lookup(Name name) throws NamingException
+ {
+ return lookup(name.toString());
+ }
+
+ public Object lookupLink(String name) throws NamingException
+ {
+ return lookup(name);
+ }
+
+ public Name composeName(Name name, Name prefix) throws NamingException
+ {
+ Name result = (Name) prefix.clone();
+ result.addAll(name);
+
+ return result;
+ }
+
+ public String composeName(String name, String prefix) throws NamingException
+ {
+ CompositeName result = new CompositeName(prefix);
+ result.addAll(new CompositeName(name));
+
+ return result.toString();
+ }
+
+ public NamingEnumeration list(String name) throws NamingException
+ {
+ Object o = lookup(name);
+ if (o == this)
+ {
+ return new ListEnumeration();
+ }
+ else if (o instanceof Context)
+ {
+ return ((Context) o).list("");
+ }
+ else
+ {
+ throw new NotContextException();
+ }
+ }
+
+ public NamingEnumeration listBindings(String name) throws NamingException
+ {
+ Object o = lookup(name);
+ if (o == this)
+ {
+ return new ListBindingEnumeration();
+ }
+ else if (o instanceof Context)
+ {
+ return ((Context) o).listBindings("");
+ }
+ else
+ {
+ throw new NotContextException();
+ }
+ }
+
+ public Object lookupLink(Name name) throws NamingException
+ {
+ return lookupLink(name.toString());
+ }
+
+ public NamingEnumeration list(Name name) throws NamingException
+ {
+ return list(name.toString());
+ }
+
+ public NamingEnumeration listBindings(Name name) throws NamingException
+ {
+ return listBindings(name.toString());
+ }
+
+ public void bind(Name name, Object obj) throws NamingException
+ {
+ throw new OperationNotSupportedException();
+ }
+
+ public void bind(String name, Object obj) throws NamingException
+ {
+ throw new OperationNotSupportedException();
+ }
+
+ public void close() throws NamingException
+ {
+ // ignore
+ }
+
+ public Context createSubcontext(Name name) throws NamingException
+ {
+ throw new OperationNotSupportedException();
+ }
+
+ public Context createSubcontext(String name) throws NamingException
+ {
+ throw new OperationNotSupportedException();
+ }
+
+ public void destroySubcontext(Name name) throws NamingException
+ {
+ throw new OperationNotSupportedException();
+ }
+
+ public void destroySubcontext(String name) throws NamingException
+ {
+ throw new OperationNotSupportedException();
+ }
+
+ public String getNameInNamespace() throws NamingException
+ {
+ return nameInNamespace;
+ }
+
+ public NameParser getNameParser(Name name) throws NamingException
+ {
+ return nameParser;
+ }
+
+ public NameParser getNameParser(String name) throws NamingException
+ {
+ return nameParser;
+ }
+
+ public void rebind(Name name, Object obj) throws NamingException
+ {
+ throw new OperationNotSupportedException();
+ }
+
+ public void rebind(String name, Object obj) throws NamingException
+ {
+ throw new OperationNotSupportedException();
+ }
+
+ public void rename(Name oldName, Name newName) throws NamingException
+ {
+ throw new OperationNotSupportedException();
+ }
+
+ public void rename(String oldName, String newName) throws NamingException
+ {
+ throw new OperationNotSupportedException();
+ }
+
+ public void unbind(Name name) throws NamingException
+ {
+ throw new OperationNotSupportedException();
+ }
+
+ public void unbind(String name) throws NamingException
+ {
+ throw new OperationNotSupportedException();
+ }
+
+ private abstract class LocalNamingEnumeration implements NamingEnumeration
+ {
+ private Iterator i = bindings.entrySet().iterator();
+
+ public boolean hasMore() throws NamingException
+ {
+ return i.hasNext();
+ }
+
+ public boolean hasMoreElements()
+ {
+ return i.hasNext();
+ }
+
+ protected Map.Entry getNext()
+ {
+ return (Map.Entry) i.next();
+ }
+
+ public void close() throws NamingException
+ { }
+ }
+
+ private class ListEnumeration extends LocalNamingEnumeration
+ {
+ public Object next() throws NamingException
+ {
+ return nextElement();
+ }
+
+ public Object nextElement()
+ {
+ Map.Entry entry = getNext();
+
+ return new NameClassPair((String) entry.getKey(), entry.getValue().getClass().getName());
+ }
+ }
+
+ private class ListBindingEnumeration extends LocalNamingEnumeration
+ {
+ public Object next() throws NamingException
+ {
+ return nextElement();
+ }
+
+ public Object nextElement()
+ {
+ Map.Entry entry = getNext();
+
+ return new Binding((String) entry.getKey(), entry.getValue());
+ }
+ }
+}
diff --git a/Final/java/client/src/old_test/java/org/apache/qpid/IBMPerfTest/JNDIBindConnectionFactory.java b/Final/java/client/src/old_test/java/org/apache/qpid/IBMPerfTest/JNDIBindConnectionFactory.java
new file mode 100644
index 0000000000..2c08f1e34a
--- /dev/null
+++ b/Final/java/client/src/old_test/java/org/apache/qpid/IBMPerfTest/JNDIBindConnectionFactory.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.IBMPerfTest;
+
+import org.apache.log4j.Level;
+import org.apache.log4j.Logger;
+import org.apache.qpid.client.AMQConnectionFactory;
+import org.apache.qpid.url.URLSyntaxException;
+
+import javax.jms.ConnectionFactory;
+import javax.naming.Context;
+import javax.naming.InitialContext;
+import javax.naming.NamingException;
+import java.io.File;
+import java.util.Hashtable;
+
+public class JNDIBindConnectionFactory
+{
+
+ public static final String CONNECTION_FACTORY_BINDING = "amq.ConnectionFactory";
+ public static final String DEFAULT_PROVIDER_FILE_PATH = System.getProperty("java.io.tmpdir") + File.separator + "IBMPerfTestsJNDI";
+ public static final String PROVIDER_URL = "file://" + DEFAULT_PROVIDER_FILE_PATH;
+ public static final String FSCONTEXT_FACTORY = "com.sun.jndi.fscontext.RefFSContextFactory";
+ public static final String DEFAULT_CONNECTION_URL = "amqp://guest:guest@clientid/testpath?brokerlist='tcp://localhost:5672'";
+
+ private static void printUsage()
+ {
+ System.out.println("Using default values: Usage:java JNDIBindConnectionFactory <connection url> [<Connection Factory Binding>] [<Provider URL>] [<JNDI Context Factory>]");
+
+ }
+
+ public static void main(String[] args)
+ {
+ Logger.getRootLogger().setLevel(Level.OFF);
+
+ String connectionFactoryBinding = CONNECTION_FACTORY_BINDING;
+ String provider = PROVIDER_URL;
+ String contextFactory = FSCONTEXT_FACTORY;
+ if (args.length == 0)
+ {
+ printUsage();
+ System.exit(1);
+ }
+
+ String connectionURL = args[0];
+
+ System.out.println("Using Connection:" + connectionURL + "\n");
+
+
+ if (args.length > 1)
+ {
+ connectionFactoryBinding = args[1];
+
+ if (args.length > 2)
+ {
+ provider = args[2];
+
+ if (args.length > 3)
+ {
+ contextFactory = args[3];
+ }
+ }
+ else
+ {
+ System.out.println("Using default File System Context Factory");
+ System.out.println("Using default Connection Factory Binding:" + connectionFactoryBinding);
+ }
+ }
+ else
+ {
+ printUsage();
+ }
+
+
+ System.out.println("File System Context Factory\n" +
+ "Connection:" + connectionURL + "\n" +
+ "Connection Factory Binding:" + connectionFactoryBinding + "\n" +
+ "JNDI Provider URL:" + provider);
+
+ if (provider.startsWith("file"))
+ {
+ File file = new File(provider.substring(provider.indexOf("://") + 3));
+
+ if (file.exists() && !file.isDirectory())
+ {
+ System.out.println("Couldn't make directory file already exists");
+ System.exit(1);
+ }
+ else
+ {
+ if (!file.exists())
+ {
+ if (!file.mkdirs())
+ {
+ System.out.println("Couldn't make directory");
+ System.exit(1);
+ }
+ }
+ }
+ }
+
+ new JNDIBindConnectionFactory(provider, connectionFactoryBinding, contextFactory, connectionURL);
+
+ }
+
+ public JNDIBindConnectionFactory(String provider, String binding, String contextFactory, String CONNECTION_URL)
+ {
+ // Set up the environment for creating the initial context
+ Hashtable env = new Hashtable(11);
+ env.put(Context.INITIAL_CONTEXT_FACTORY, contextFactory);
+
+ env.put(Context.PROVIDER_URL, provider);
+
+ try
+ {
+ // Create the initial context
+ Context ctx = new InitialContext(env);
+
+ // Create the object to be bound
+ ConnectionFactory factory = null;
+
+ try
+ {
+ factory = new AMQConnectionFactory(CONNECTION_URL);
+
+
+ try
+ {
+ Object obj = ctx.lookup(binding);
+
+ if (obj != null)
+ {
+ System.out.println("Un-binding previous Connection Factory");
+ ctx.unbind(binding);
+ }
+ }
+ catch (NamingException e)
+ {
+ System.out.println("Operation failed: " + e);
+ }
+
+ // Perform the bind
+ ctx.bind(binding, factory);
+ System.out.println("Bound Connection Factory:" + binding);
+
+ // Check that it is bound
+ Object obj = ctx.lookup(binding);
+ System.out.println("Connection URL:" + ((AMQConnectionFactory) obj).getConnectionURL());
+
+ System.out.println("JNDI FS Context:" + provider);
+ }
+ catch (NamingException amqe)
+ {
+ System.out.println("Operation failed: " + amqe);
+ }
+ catch (URLSyntaxException e)
+ {
+ System.out.println("Operation failed: " + e);
+ }
+
+ }
+ catch (NamingException e)
+ {
+ System.out.println("Operation failed: " + e);
+ }
+ }
+}
diff --git a/Final/java/client/src/old_test/java/org/apache/qpid/IBMPerfTest/JNDIBindQueue.java b/Final/java/client/src/old_test/java/org/apache/qpid/IBMPerfTest/JNDIBindQueue.java
new file mode 100644
index 0000000000..10e8b94311
--- /dev/null
+++ b/Final/java/client/src/old_test/java/org/apache/qpid/IBMPerfTest/JNDIBindQueue.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.IBMPerfTest;
+
+import org.apache.log4j.Level;
+import org.apache.log4j.Logger;
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.client.AMQQueue;
+import org.apache.qpid.client.AMQSession;
+
+import javax.jms.Connection;
+import javax.jms.JMSException;
+import javax.jms.Queue;
+import javax.jms.Session;
+import javax.naming.Context;
+import javax.naming.InitialContext;
+import javax.naming.NamingException;
+import java.io.File;
+import java.util.Hashtable;
+
+public class JNDIBindQueue
+{
+ public static final String DEFAULT_PROVIDER_FILE_PATH = System.getProperty("java.io.tmpdir") + File.separator + "IBMPerfTestsJNDI";
+ public static final String PROVIDER_URL = "file://" + DEFAULT_PROVIDER_FILE_PATH;
+ public static final String FSCONTEXT_FACTORY = "com.sun.jndi.fscontext.RefFSContextFactory";
+
+ Connection _connection = null;
+ Context _ctx = null;
+
+
+ public JNDIBindQueue(String queueBinding, String queueName, String provider, String contextFactory)
+ {
+ // Set up the environment for creating the initial context
+ Hashtable env = new Hashtable(11);
+ env.put(Context.INITIAL_CONTEXT_FACTORY, contextFactory);
+
+ env.put(Context.PROVIDER_URL, provider);
+
+ try
+ {
+ // Create the initial context
+ _ctx = new InitialContext(env);
+
+ // Create the object to be bound
+
+ try
+ {
+ _connection = new AMQConnection("amqp://guest:guest@clientid/test?brokerlist='tcp://localhost:5672'");
+ System.out.println("Connected");
+ }
+ catch (Exception amqe)
+ {
+ System.out.println("Unable to create AMQConnectionFactory:" + amqe);
+ }
+
+ if (_connection != null)
+ {
+ bindQueue(queueName, queueBinding);
+ }
+
+ // Check that it is bound
+ Object obj = _ctx.lookup(queueBinding);
+
+ System.out.println("Bound Queue:" + ((AMQQueue) obj).toURL());
+
+ System.out.println("JNDI FS Context:" + provider);
+
+ }
+ catch (NamingException e)
+ {
+ System.out.println("Operation failed: " + e);
+ }
+ finally
+ {
+ try
+ {
+ if (_connection != null)
+ {
+ _connection.close();
+ }
+ }
+ catch (JMSException closeE)
+ {
+ System.out.println("Connection closing failed: " + closeE);
+ }
+ }
+
+
+ }
+
+
+ private void bindQueue(String queueName, String queueBinding) throws NamingException
+ {
+
+ try
+ {
+ Object obj = _ctx.lookup(queueBinding);
+
+ if (obj != null)
+ {
+ System.out.println("Un-binding exisiting object");
+ _ctx.unbind(queueBinding);
+ }
+ }
+ catch (NamingException e)
+ {
+
+ }
+
+ Queue queue = null;
+ try
+ {
+
+ Session session = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ if (session != null)
+ {
+ queue = ((AMQSession) session).createQueue(queueName);
+ }
+ }
+ catch (JMSException jmse)
+ {
+ System.out.println("Unable to create Queue:" + jmse);
+ }
+
+ // Perform the bind
+ _ctx.bind(queueBinding, queue);
+ }
+
+
+ public static void main(String[] args)
+ {
+ Logger.getRootLogger().setLevel(Level.OFF);
+
+ String provider = JNDIBindQueue.PROVIDER_URL;
+ String contextFactory = JNDIBindQueue.FSCONTEXT_FACTORY;
+
+ if (args.length > 1)
+ {
+ String binding = args[0];
+ String queueName = args[1];
+
+ if (args.length > 2)
+ {
+ provider = args[2];
+
+ if (args.length > 3)
+ {
+ contextFactory = args[3];
+ }
+ }
+ else
+ {
+ System.out.println("Using default File System Context Factory");
+ }
+
+ System.out.println("File System Context Factory\n" +
+ "Binding Queue:'" + queueName + "' to '" + binding + "'\n" +
+ "JNDI Provider URL:" + provider);
+
+ if (provider.startsWith("file"))
+ {
+ File file = new File(provider.substring(provider.indexOf("://") + 3));
+
+ if (file.exists() && !file.isDirectory())
+ {
+ System.out.println("Couldn't make directory file already exists");
+ System.exit(1);
+ }
+ else
+ {
+ if (!file.exists())
+ {
+ if (!file.mkdirs())
+ {
+ System.out.println("Couldn't make directory");
+ System.exit(1);
+ }
+ }
+ }
+ }
+
+
+ new JNDIBindQueue(binding, queueName, provider, contextFactory);
+
+ }
+ else
+ {
+ System.out.println("Using Defaults: Usage:java JNDIBindQueue <Binding> <queue name> [<Provider URL> [<JNDI Context Factory>]]");
+ }
+
+ }
+
+
+}
diff --git a/Final/java/client/src/old_test/java/org/apache/qpid/IBMPerfTest/JNDIBindTopic.java b/Final/java/client/src/old_test/java/org/apache/qpid/IBMPerfTest/JNDIBindTopic.java
new file mode 100644
index 0000000000..ca071c1187
--- /dev/null
+++ b/Final/java/client/src/old_test/java/org/apache/qpid/IBMPerfTest/JNDIBindTopic.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.IBMPerfTest;
+
+import org.apache.log4j.Level;
+import org.apache.log4j.Logger;
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.client.AMQSession;
+import org.apache.qpid.client.AMQTopic;
+
+import javax.jms.Connection;
+import javax.jms.JMSException;
+import javax.jms.Session;
+import javax.jms.Topic;
+import javax.naming.Context;
+import javax.naming.InitialContext;
+import javax.naming.NamingException;
+import java.io.File;
+import java.util.Hashtable;
+
+public class JNDIBindTopic
+{
+ public static final String DEFAULT_PROVIDER_FILE_PATH = System.getProperty("java.io.tmpdir") + File.separator + "IBMPerfTestsJNDI";
+ public static final String PROVIDER_URL = "file://" + DEFAULT_PROVIDER_FILE_PATH;
+
+ public static final String FSCONTEXT_FACTORY = "com.sun.jndi.fscontext.RefFSContextFactory";
+
+ Connection _connection = null;
+ Context _ctx = null;
+
+
+ public JNDIBindTopic(String topicBinding, String topicName, String provider, String contextFactory)
+ {
+ // Set up the environment for creating the initial context
+ Hashtable env = new Hashtable(11);
+ env.put(Context.INITIAL_CONTEXT_FACTORY, contextFactory);
+
+ env.put(Context.PROVIDER_URL, provider);
+
+ try
+ {
+ // Create the initial context
+ _ctx = new InitialContext(env);
+
+ // Create the object to be bound
+
+ try
+ {
+ _connection = new AMQConnection("amqp://guest:guest@clientid/test?brokerlist='tcp://localhost:5672'");
+ System.out.println("Connected");
+ }
+ catch (Exception amqe)
+ {
+ System.out.println("Unable to create AMQConnectionFactory:" + amqe);
+ }
+
+ if (_connection != null)
+ {
+ bindTopic(topicName, topicBinding);
+ }
+
+ // Check that it is bound
+ Object obj = _ctx.lookup(topicBinding);
+
+ System.out.println("Bound Queue:" + ((AMQTopic) obj).toURL());
+
+ System.out.println("JNDI FS Context:" + provider);
+
+ }
+ catch (NamingException e)
+ {
+ System.out.println("Operation failed: " + e);
+ }
+ finally
+ {
+ try
+ {
+ if (_connection != null)
+ {
+ _connection.close();
+ }
+ }
+ catch (JMSException closeE)
+ {
+ System.out.println("Operation failed: " + closeE);
+ }
+ }
+ }
+
+
+ private void bindTopic(String topicName, String topicBinding) throws NamingException
+ {
+
+ try
+ {
+ Object obj = _ctx.lookup(topicBinding);
+
+ if (obj != null)
+ {
+ System.out.println("Un-binding exisiting object");
+ _ctx.unbind(topicBinding);
+ }
+ }
+ catch (NamingException e)
+ {
+
+ }
+
+ Topic topic = null;
+ try
+ {
+
+ Session session = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ if (session != null)
+ {
+ topic = ((AMQSession) session).createTopic(topicName);
+ }
+ }
+ catch (JMSException jmse)
+ {
+ System.out.println("Unable to create Topic:" + jmse);
+ }
+
+ // Perform the bind
+ _ctx.bind(topicBinding, topic);
+ }
+
+
+ public static void main(String[] args)
+ {
+ Logger.getRootLogger().setLevel(Level.OFF);
+
+ String provider = JNDIBindTopic.PROVIDER_URL;
+ String contextFactory = JNDIBindTopic.FSCONTEXT_FACTORY;
+
+ if (args.length > 1)
+ {
+ String binding = args[0];
+ String queueName = args[1];
+
+ if (args.length > 2)
+ {
+ provider = args[2];
+
+ if (args.length > 3)
+ {
+ contextFactory = args[3];
+ }
+ }
+ else
+ {
+ System.out.println("Using default File System Context Factory");
+ }
+
+ System.out.println("File System Context Factory\n" +
+ "Binding Topic:'" + queueName + "' to '" + binding + "'\n" +
+ "JNDI Provider URL:" + provider);
+
+
+ if (provider.startsWith("file"))
+ {
+ File file = new File(provider.substring(provider.indexOf("://") + 3));
+
+ if (file.exists() && !file.isDirectory())
+ {
+ System.out.println("Couldn't make directory file already exists");
+ System.exit(1);
+ }
+ else
+ {
+ if (!file.exists())
+ {
+ if (!file.mkdirs())
+ {
+ System.out.println("Couldn't make directory");
+ System.exit(1);
+ }
+ }
+ }
+ }
+
+ new JNDIBindTopic(binding, queueName, provider, contextFactory);
+
+ }
+ else
+ {
+ System.out.println("Usage:java JNDIBindTopic <Binding> <topic name> [<Provider URL> [<JNDI Context Factory>]]");
+ }
+
+ }
+
+
+}
diff --git a/Final/java/client/src/old_test/java/org/apache/qpid/IBMPerfTest/README.txt b/Final/java/client/src/old_test/java/org/apache/qpid/IBMPerfTest/README.txt
new file mode 100644
index 0000000000..95ee9f9c77
--- /dev/null
+++ b/Final/java/client/src/old_test/java/org/apache/qpid/IBMPerfTest/README.txt
@@ -0,0 +1,11 @@
+These JNDI setup tools are mainly for use in conjunction with the IBM JMS Performance Harness available here:
+The jar should be placed in the client/test/lib/ directory.
+
+http://www.alphaworks.ibm.com/tech/perfharness
+
+
+These JNDI classes use the the SUN FileSystem context.
+There are two jar files that should be placed in your client/test/lib directory.
+
+http://javashoplm.sun.com/ECom/docs/Welcome.jsp?StoreId=22&PartDetailId=7110-jndi-1.2.1-oth-JPR&SiteId=JSC&TransactionId=noreg
+
diff --git a/Final/java/client/src/old_test/java/org/apache/qpid/cluster/Client.java b/Final/java/client/src/old_test/java/org/apache/qpid/cluster/Client.java
new file mode 100644
index 0000000000..cf8059a143
--- /dev/null
+++ b/Final/java/client/src/old_test/java/org/apache/qpid/cluster/Client.java
@@ -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.
+ *
+ */
+package org.apache.qpid.cluster;
+
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.client.AMQSession;
+import org.apache.qpid.client.AMQTopic;
+import org.apache.qpid.client.AMQQueue;
+import org.apache.qpid.AMQException;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.exchange.ExchangeDefaults;
+import org.apache.qpid.url.URLSyntaxException;
+
+import javax.jms.MessageListener;
+import javax.jms.Message;
+import javax.jms.Session;
+import javax.jms.JMSException;
+import javax.jms.MessageProducer;
+import javax.jms.TextMessage;
+import java.util.Random;
+
+public class Client
+{
+ private final Random random = new Random();
+ private final String name;
+ private final Session session;
+ private final MessageProducer topicProducer;
+ private final MessageProducer queueProducer;
+
+ Client(AMQConnection connection, String name) throws JMSException, InterruptedException
+ {
+ this.name = name;
+ session = connection.createSession(false, AMQSession.NO_ACKNOWLEDGE);
+
+ AMQTopic topic = new AMQTopic(((AMQSession)session).getDefaultTopicExchangeName(), new AMQShortString("cluster_test_topic"));
+ AMQQueue queue = new AMQQueue(((AMQSession)session).getDefaultQueueExchangeName(), new AMQShortString("cluster_test_queue"));
+
+ topicProducer = session.createProducer(topic);
+ queueProducer = session.createProducer(queue);
+
+ //subscribe to a known topic
+ session.createConsumer(topic).setMessageListener(new TopicHandler());
+ //subscribe to a known queue
+ session.createConsumer(queue).setMessageListener(new QueueHandler());
+
+ connection.start();
+
+ while(true)
+ {
+ Thread.sleep(random.nextInt(60000));
+ sendToQueue(name + ":" + randomString(5));
+ }
+ }
+
+ private synchronized void sendToTopic(String message) throws JMSException
+ {
+ topicProducer.send(session.createTextMessage(message));
+ }
+
+ private synchronized void sendToQueue(String message) throws JMSException
+ {
+ queueProducer.send(session.createTextMessage(message));
+ }
+
+ private String randomString(int length){
+ char[] c = new char[length];
+ for(int i = 0; i < length; i++)
+ {
+ c[i] = (char) ('A' + random.nextInt(26));
+ }
+ return new String(c);
+ }
+
+ private class QueueHandler implements MessageListener
+ {
+ public void onMessage(Message message)
+ {
+ try
+ {
+ sendToTopic(((TextMessage) message).getText());
+ }
+ catch (JMSException e)
+ {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ private class TopicHandler implements MessageListener
+ {
+ public void onMessage(Message message)
+ {
+ try
+ {
+ System.out.println(((TextMessage) message).getText());
+ }
+ catch (JMSException e)
+ {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ public static void main(String[] argv) throws AMQException, JMSException, InterruptedException, URLSyntaxException
+ {
+ //assume args describe the set of brokers to try
+
+ String clientName = argv.length > 1 ? argv[1] : "testClient";
+ new Client(new AMQConnection(argv.length > 0 ? argv[0] : "vm://:1", "guest", "guest", clientName, "/test"), clientName);
+ }
+}
diff --git a/Final/java/client/src/old_test/java/org/apache/qpid/codec/BasicDeliverTest.java b/Final/java/client/src/old_test/java/org/apache/qpid/codec/BasicDeliverTest.java
new file mode 100644
index 0000000000..1db7e200bd
--- /dev/null
+++ b/Final/java/client/src/old_test/java/org/apache/qpid/codec/BasicDeliverTest.java
@@ -0,0 +1,277 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.codec;
+
+import org.apache.qpid.framing.*;
+import org.apache.mina.common.*;
+import org.apache.mina.common.support.BaseIoSession;
+import org.apache.mina.filter.codec.ProtocolDecoderOutput;
+import org.apache.mina.filter.codec.ProtocolEncoderOutput;
+
+import java.net.SocketAddress;
+
+/**
+ */
+public class BasicDeliverTest
+{
+ public static void main(String[] argv) throws Exception
+ {
+ BasicDeliverTest test = new BasicDeliverTest();
+
+ //warm up:
+ test.encode(512, 100000);
+
+ //real tests:
+ test.encode(16, 10000, 15);
+ test.encode(32, 10000, 15);
+ test.encode(64, 10000, 15);
+ test.encode(128, 10000, 15);
+ test.encode(256, 10000, 15);
+ test.encode(512, 10000, 15);
+ test.encode(1024, 10000, 15);
+ test.encode(2048, 10000, 15);
+
+ test.decode(16, 10000, 15);
+ test.decode(32, 10000, 15);
+ test.decode(64, 10000, 15);
+ test.decode(128, 10000, 15);
+ test.decode(256, 10000, 15);
+ test.decode(512, 10000, 15);
+ test.decode(1024, 10000, 15);
+ test.decode(2048, 10000, 15);
+ }
+
+ void decode(int size, int count, int iterations) throws Exception
+ {
+ long min = Long.MAX_VALUE;
+ long max = 0;
+ long total = 0;
+ for (int i = 0; i < iterations; i++)
+ {
+ long time = decode(size, count);
+ total += time;
+ if (time < min)
+ {
+ min = time;
+ }
+ if (time > max)
+ {
+ max = time;
+ }
+ }
+ System.out.println("Decoded " + count + " messages of " + size +
+ " bytes: avg=" + (total / iterations) + ", min=" + min + ", max=" + max);
+ }
+
+
+ long decode(int size, int count) throws Exception
+ {
+ AMQDataBlock block = getDataBlock(size);
+ ByteBuffer data = ByteBuffer.allocate((int) block.getSize()); // XXX: Is cast a problem?
+ block.writePayload(data);
+ data.flip();
+ AMQDecoder decoder = new AMQDecoder(false);
+ long start = System.currentTimeMillis();
+ for (int i = 0; i < count; i++)
+ {
+ decoder.decode(session, data, decoderOutput);
+ data.rewind();
+ }
+ return System.currentTimeMillis() - start;
+ }
+
+ void encode(int size, int count, int iterations) throws Exception
+ {
+ long min = Long.MAX_VALUE;
+ long max = 0;
+ long total = 0;
+ for (int i = 0; i < iterations; i++)
+ {
+ long time = encode(size, count);
+ total += time;
+ if (time < min)
+ {
+ min = time;
+ }
+ if (time > max)
+ {
+ max = time;
+ }
+ }
+ System.out.println("Encoded " + count + " messages of " + size +
+ " bytes: avg=" + (total / iterations) + ", min=" + min + ", max=" + max);
+ }
+
+ long encode(int size, int count) throws Exception
+ {
+ IoSession session = null;
+ AMQDataBlock block = getDataBlock(size);
+ AMQEncoder encoder = new AMQEncoder();
+ long start = System.currentTimeMillis();
+ for (int i = 0; i < count; i++)
+ {
+ encoder.encode(session, block, encoderOutput);
+ }
+ return System.currentTimeMillis() - start;
+ }
+
+ private final ProtocolEncoderOutput encoderOutput = new ProtocolEncoderOutput()
+ {
+
+ public void write(ByteBuffer byteBuffer)
+ {
+ }
+
+ public void mergeAll()
+ {
+ }
+
+ public WriteFuture flush()
+ {
+ return null;
+ }
+ };
+
+ private final ProtocolDecoderOutput decoderOutput = new ProtocolDecoderOutput()
+ {
+ public void write(Object object)
+ {
+ }
+
+ public void flush()
+ {
+ }
+ };
+
+ private final IoSession session = new BaseIoSession()
+ {
+
+ protected void updateTrafficMask()
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ 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 TransportType getTransportType()
+ {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public SocketAddress getRemoteAddress()
+ {
+ return null; //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 getScheduledWriteRequests()
+ {
+ return 0; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public int getScheduledWriteBytes()
+ {
+ return 0; //To change body of implemented methods use File | Settings | File Templates.
+ }
+ };
+
+ private static final char[] DATA = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray();
+
+ static CompositeAMQDataBlock getDataBlock(int size)
+ {
+ //create a frame representing message delivery
+ AMQFrame[] frames = new AMQFrame[3];
+ frames[0] = wrapBody(createBasicDeliverBody());
+ frames[1] = wrapBody(createContentHeaderBody());
+ frames[2] = wrapBody(createContentBody(size));
+
+ return new CompositeAMQDataBlock(frames);
+ }
+
+ static AMQFrame wrapBody(AMQBody body)
+ {
+ AMQFrame frame = new AMQFrame(1, body);
+ return frame;
+ }
+
+ static ContentBody createContentBody(int size)
+ {
+ ContentBody body = new ContentBody();
+ body.payload = ByteBuffer.allocate(size);
+ for (int i = 0; i < size; i++)
+ {
+ body.payload.put((byte) DATA[i % DATA.length]);
+ }
+ return body;
+ }
+
+ static ContentHeaderBody createContentHeaderBody()
+ {
+ ContentHeaderBody body = new ContentHeaderBody();
+ body.properties = new BasicContentHeaderProperties();
+ body.weight = 1;
+ body.classId = 6;
+ return body;
+ }
+
+ static BasicDeliverBody createBasicDeliverBody()
+ {
+ BasicDeliverBody body = new BasicDeliverBody((byte) 8, (byte) 0,
+ BasicDeliverBody.getClazz((byte) 8, (byte) 0),
+ BasicDeliverBody.getMethod((byte) 8, (byte) 0),
+ new AMQShortString("myConsumerTag"), 1,
+ new AMQShortString("myExchange"), false,
+ new AMQShortString("myRoutingKey"));
+ return body;
+ }
+}
diff --git a/Final/java/client/src/old_test/java/org/apache/qpid/codec/Client.java b/Final/java/client/src/old_test/java/org/apache/qpid/codec/Client.java
new file mode 100644
index 0000000000..3886021277
--- /dev/null
+++ b/Final/java/client/src/old_test/java/org/apache/qpid/codec/Client.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.codec;
+
+import org.apache.mina.transport.socket.nio.SocketConnector;
+import org.apache.mina.common.ConnectFuture;
+import org.apache.mina.common.IoHandlerAdapter;
+import org.apache.mina.common.IoSession;
+import org.apache.mina.filter.codec.ProtocolCodecFilter;
+import org.apache.qpid.framing.AMQDataBlock;
+import org.apache.qpid.framing.AMQFrame;
+import org.apache.qpid.framing.BasicDeliverBody;
+import org.apache.qpid.framing.ContentBody;
+
+import java.net.InetSocketAddress;
+
+public class Client extends IoHandlerAdapter
+{
+ //private static final int[] DEFAULT_SIZES = new int[]{1024, 512, 256, 128, 56};
+ //private static final int[] DEFAULT_SIZES = new int[]{256, 256, 256, 256, 256, 512, 512, 512, 512, 512};
+ private static final int[] DEFAULT_SIZES = new int[]{256, 512, 256, 512, 256, 512, 256, 512, 256, 512};
+ //private static final int[] DEFAULT_SIZES = new int[]{1024, 1024, 1024, 1024, 1024};
+
+ private final IoSession _session;
+ private final long _start;
+ private final int _size;
+ private final int _count;
+ private int _received;
+ private boolean _closed;
+
+ Client(String host, int port, int size, int count) throws Exception
+ {
+ _count = count;
+ _size = size;
+ AMQDataBlock block = BasicDeliverTest.getDataBlock(size);
+
+ InetSocketAddress address = new InetSocketAddress(host, port);
+ ConnectFuture future = new SocketConnector().connect(address, this);
+ future.join();
+ _session = future.getSession();
+
+ _start = System.currentTimeMillis();
+ for(int i = 0; i < count; i++)
+ {
+ _session.write(block);
+ }
+ }
+
+ void close()
+ {
+ long time = System.currentTimeMillis() - _start;
+ System.out.println("Received " + _received + " messages of " + _size
+ + " bytes in " + time + "ms.");
+ _session.close();
+ synchronized(this)
+ {
+ _closed = true;
+ notify();
+ }
+ }
+
+ void waitForClose() throws InterruptedException
+ {
+ synchronized(this)
+ {
+ while(!_closed)
+ {
+ wait();
+ }
+ }
+ }
+
+ public void sessionCreated(IoSession session) throws Exception
+ {
+ session.getFilterChain().addLast("protocolFilter", new ProtocolCodecFilter(new AMQCodecFactory(false)));
+ }
+
+ public void messageReceived(IoSession session, Object object) throws Exception
+ {
+ if(isContent(object) && ++_received == _count) close();
+ }
+
+ public void exceptionCaught(IoSession session, Throwable throwable) throws Exception
+ {
+ throwable.printStackTrace();
+ close();
+ }
+
+ private static boolean isDeliver(Object o)
+ {
+ return o instanceof AMQFrame && ((AMQFrame) o).getBodyFrame() instanceof BasicDeliverBody;
+ }
+
+ private static boolean isContent(Object o)
+ {
+ return o instanceof AMQFrame && ((AMQFrame) o).getBodyFrame() instanceof ContentBody;
+ }
+
+ public static void main(String[] argv) throws Exception
+ {
+ String host = argv.length > 0 ? argv[0] : "localhost";
+ int port = argv.length > 1 ? Integer.parseInt(argv[1]) : 8888;
+ int count = argv.length > 2 ? Integer.parseInt(argv[2]) : 10000;
+ int[] sizes = argv.length > 3 ? new int[]{Integer.parseInt(argv[3])} : DEFAULT_SIZES;
+
+ System.out.println("Connecting to " + host + ":" + port);
+
+ for(int i = 0; i < sizes.length; i++)
+ {
+ new Client(host, port, sizes[i], count).waitForClose();
+ Thread.sleep(1000);
+ }
+ }
+
+}
diff --git a/Final/java/client/src/old_test/java/org/apache/qpid/codec/Server.java b/Final/java/client/src/old_test/java/org/apache/qpid/codec/Server.java
new file mode 100644
index 0000000000..fa4295e0b2
--- /dev/null
+++ b/Final/java/client/src/old_test/java/org/apache/qpid/codec/Server.java
@@ -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.
+ *
+ */
+package org.apache.qpid.codec;
+
+import org.apache.mina.common.IoHandlerAdapter;
+import org.apache.mina.common.IoSession;
+import org.apache.mina.transport.socket.nio.SocketAcceptor;
+import org.apache.mina.util.SessionUtil;
+import org.apache.mina.filter.codec.ProtocolCodecFilter;
+import org.apache.qpid.framing.AMQFrame;
+import org.apache.qpid.framing.CompositeAMQDataBlock;
+
+import java.net.InetSocketAddress;
+
+public class Server extends IoHandlerAdapter
+{
+ Server(int port) throws Exception
+ {
+ new SocketAcceptor().bind(new InetSocketAddress(port), this);
+ System.out.println("Listening on " + port);
+ }
+
+ public void sessionCreated(IoSession session) throws Exception
+ {
+ SessionUtil.initialize(session);
+ session.getFilterChain().addLast("protocolFilter", new ProtocolCodecFilter(new AMQCodecFactory(false)));
+ }
+
+ public void messageReceived(IoSession session, Object object) throws Exception
+ {
+ getAccumulator(session).received(session, (AMQFrame) object);
+ }
+
+ public void sessionOpened(IoSession session) throws Exception
+ {
+ System.out.println("sessionOpened()");
+ }
+
+ public void sessionClosed(IoSession session) throws Exception
+ {
+ System.out.println("sessionClosed()");
+ }
+
+ public void exceptionCaught(IoSession session, Throwable t) throws Exception
+ {
+ System.out.println("exceptionCaught()");
+ t.printStackTrace();
+ session.close();
+ }
+
+ private Accumulator getAccumulator(IoSession session)
+ {
+ Accumulator a = (Accumulator) session.getAttribute(ACCUMULATOR);
+ if(a == null)
+ {
+ a = new Accumulator();
+ session.setAttribute(ACCUMULATOR, a);
+ }
+ return a;
+ }
+
+ private static final String ACCUMULATOR = Accumulator.class.getName();
+
+ private static class Accumulator
+ {
+ private final AMQFrame[] frames = new AMQFrame[3];
+ private int i;
+
+ void received(IoSession session, AMQFrame frame)
+ {
+ frames[i++] = frame;
+ if(i >= frames.length)
+ {
+ i = 0;
+ session.write(new CompositeAMQDataBlock(frames));
+ }
+ }
+ }
+
+ public static void main(String[] argv) throws Exception
+ {
+ int port = argv.length > 0 ? Integer.parseInt(argv[0]) : 8888;
+ new Server(port);
+ }
+}
diff --git a/Final/java/client/src/old_test/java/org/apache/qpid/config/AMQConnectionFactoryInitialiser.java b/Final/java/client/src/old_test/java/org/apache/qpid/config/AMQConnectionFactoryInitialiser.java
new file mode 100644
index 0000000000..cac0064785
--- /dev/null
+++ b/Final/java/client/src/old_test/java/org/apache/qpid/config/AMQConnectionFactoryInitialiser.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.config;
+
+import org.apache.qpid.client.AMQConnectionFactory;
+import org.apache.qpid.config.ConnectionFactoryInitialiser;
+import org.apache.qpid.config.ConnectorConfig;
+
+import javax.jms.ConnectionFactory;
+
+class AMQConnectionFactoryInitialiser implements ConnectionFactoryInitialiser
+{
+ public ConnectionFactory getFactory(ConnectorConfig config)
+ {
+ return new AMQConnectionFactory(config.getHost(), config.getPort(), "/test_path");
+ }
+}
diff --git a/Final/java/client/src/old_test/java/org/apache/qpid/config/AbstractConfig.java b/Final/java/client/src/old_test/java/org/apache/qpid/config/AbstractConfig.java
new file mode 100644
index 0000000000..04381d66a0
--- /dev/null
+++ b/Final/java/client/src/old_test/java/org/apache/qpid/config/AbstractConfig.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.config;
+
+public abstract class AbstractConfig
+{
+ public boolean setOptions(String[] argv)
+ {
+ try
+ {
+ for(int i = 0; i < argv.length - 1; i += 2)
+ {
+ String key = argv[i];
+ String value = argv[i+1];
+ setOption(key, value);
+ }
+ return true;
+ }
+ catch(Exception e)
+ {
+ System.out.println(e.getMessage());
+ }
+ return false;
+ }
+
+ protected int parseInt(String msg, String i)
+ {
+ try
+ {
+ return Integer.parseInt(i);
+ }
+ catch(NumberFormatException e)
+ {
+ throw new RuntimeException(msg + ": " + i);
+ }
+ }
+
+ protected long parseLong(String msg, String i)
+ {
+ try
+ {
+ return Long.parseLong(i);
+ }
+ catch(NumberFormatException e)
+ {
+ throw new RuntimeException(msg + ": " + i);
+ }
+ }
+
+ public abstract void setOption(String key, String value);
+}
diff --git a/Final/java/client/src/old_test/java/org/apache/qpid/config/ConnectionFactoryInitialiser.java b/Final/java/client/src/old_test/java/org/apache/qpid/config/ConnectionFactoryInitialiser.java
new file mode 100644
index 0000000000..a9984eb09a
--- /dev/null
+++ b/Final/java/client/src/old_test/java/org/apache/qpid/config/ConnectionFactoryInitialiser.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.config;
+
+import javax.jms.ConnectionFactory;
+import javax.jms.JMSException;
+
+public interface ConnectionFactoryInitialiser
+{
+ public ConnectionFactory getFactory(ConnectorConfig config) throws JMSException;
+}
diff --git a/Final/java/client/src/old_test/java/org/apache/qpid/config/Connector.java b/Final/java/client/src/old_test/java/org/apache/qpid/config/Connector.java
new file mode 100644
index 0000000000..ff2377f087
--- /dev/null
+++ b/Final/java/client/src/old_test/java/org/apache/qpid/config/Connector.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.config;
+
+import javax.jms.Connection;
+import javax.jms.ConnectionFactory;
+
+public class Connector
+{
+ public Connection createConnection(ConnectorConfig config) throws Exception
+ {
+ return getConnectionFactory(config).createConnection();
+ }
+
+ ConnectionFactory getConnectionFactory(ConnectorConfig config) throws Exception
+ {
+ String factory = config.getFactory();
+ if(factory == null) factory = AMQConnectionFactoryInitialiser.class.getName();
+ System.out.println("Using " + factory);
+ return ((ConnectionFactoryInitialiser) Class.forName(factory).newInstance()).getFactory(config);
+ }
+}
diff --git a/Final/java/client/src/old_test/java/org/apache/qpid/config/ConnectorConfig.java b/Final/java/client/src/old_test/java/org/apache/qpid/config/ConnectorConfig.java
new file mode 100644
index 0000000000..b120ed3f12
--- /dev/null
+++ b/Final/java/client/src/old_test/java/org/apache/qpid/config/ConnectorConfig.java
@@ -0,0 +1,28 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.config;
+
+public interface ConnectorConfig
+{
+ public String getHost();
+ public int getPort();
+ public String getFactory();
+}
diff --git a/Final/java/client/src/old_test/java/org/apache/qpid/config/JBossConnectionFactoryInitialiser.java b/Final/java/client/src/old_test/java/org/apache/qpid/config/JBossConnectionFactoryInitialiser.java
new file mode 100644
index 0000000000..44285efd96
--- /dev/null
+++ b/Final/java/client/src/old_test/java/org/apache/qpid/config/JBossConnectionFactoryInitialiser.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.config;
+
+import org.apache.qpid.config.ConnectionFactoryInitialiser;
+import org.apache.qpid.config.ConnectorConfig;
+
+import javax.jms.ConnectionFactory;
+import javax.jms.JMSException;
+import javax.management.MBeanServerConnection;
+import javax.management.ObjectName;
+import javax.management.MBeanException;
+import javax.naming.InitialContext;
+import javax.naming.NamingException;
+import javax.naming.NameNotFoundException;
+import java.util.Hashtable;
+
+public class JBossConnectionFactoryInitialiser implements ConnectionFactoryInitialiser
+{
+ public ConnectionFactory getFactory(ConnectorConfig config) throws JMSException
+ {
+ ConnectionFactory cf = null;
+ InitialContext ic = null;
+ Hashtable ht = new Hashtable();
+ ht.put(InitialContext.INITIAL_CONTEXT_FACTORY, "org.jnp.interfaces.NamingContextFactory");
+ String jbossHost = System.getProperty("jboss.host", "eqd-lxamq01");
+ String jbossPort = System.getProperty("jboss.port", "1099");
+ ht.put(InitialContext.PROVIDER_URL, "jnp://" + jbossHost + ":" + jbossPort);
+ ht.put(InitialContext.URL_PKG_PREFIXES, "org.jboss.naming:org.jnp.interfaces");
+
+ try
+ {
+ ic = new InitialContext(ht);
+ if (!doesDestinationExist("topictest.messages", ic))
+ {
+ deployTopic("topictest.messages", ic);
+ }
+ if (!doesDestinationExist("topictest.control", ic))
+ {
+ deployTopic("topictest.control", ic);
+ }
+
+ cf = (ConnectionFactory) ic.lookup("/ConnectionFactory");
+ return cf;
+ }
+ catch (NamingException e)
+ {
+ throw new JMSException("Unable to lookup object: " + e);
+ }
+ catch (Exception e)
+ {
+ throw new JMSException("Error creating topic: " + e);
+ }
+ }
+
+ private boolean doesDestinationExist(String name, InitialContext ic) throws Exception
+ {
+ try
+ {
+ ic.lookup("/" + name);
+ }
+ catch (NameNotFoundException e)
+ {
+ return false;
+ }
+ return true;
+ }
+
+ private void deployTopic(String name, InitialContext ic) throws Exception
+ {
+ MBeanServerConnection mBeanServer = lookupMBeanServerProxy(ic);
+
+ ObjectName serverObjectName = new ObjectName("jboss.messaging:service=ServerPeer");
+
+ String jndiName = "/" + name;
+ try
+ {
+ mBeanServer.invoke(serverObjectName, "createTopic",
+ new Object[]{name, jndiName},
+ new String[]{"java.lang.String", "java.lang.String"});
+ }
+ catch (MBeanException e)
+ {
+ System.err.println("Error: " + e);
+ System.err.println("Cause: " + e.getCause());
+ }
+ }
+
+ private MBeanServerConnection lookupMBeanServerProxy(InitialContext ic) throws NamingException
+ {
+ return (MBeanServerConnection) ic.lookup("jmx/invoker/RMIAdaptor");
+ }
+}
diff --git a/Final/java/client/src/old_test/java/org/apache/qpid/flow/ChannelFlowTest.java b/Final/java/client/src/old_test/java/org/apache/qpid/flow/ChannelFlowTest.java
new file mode 100644
index 0000000000..cb8adae18c
--- /dev/null
+++ b/Final/java/client/src/old_test/java/org/apache/qpid/flow/ChannelFlowTest.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.flow;
+
+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.exchange.ExchangeDefaults;
+import org.apache.qpid.framing.AMQShortString;
+
+import javax.jms.Message;
+import javax.jms.MessageListener;
+import javax.jms.MessageProducer;
+
+public class ChannelFlowTest implements MessageListener
+{
+ private int sent;
+ private int received;
+
+ ChannelFlowTest(String broker) throws Exception
+ {
+ this(new AMQConnection(broker, "guest", "guest", randomize("Client"), "/test"));
+ }
+
+ ChannelFlowTest(AMQConnection connection) throws Exception
+ {
+ this(connection, new AMQQueue(connection.getDefaultQueueExchangeName(), new AMQShortString(randomize("ChannelFlowTest")), true));
+ }
+
+ ChannelFlowTest(AMQConnection connection, AMQDestination destination) throws Exception
+ {
+ AMQSession session = (AMQSession) connection.createSession(false, AMQSession.NO_ACKNOWLEDGE, 50,25);
+
+ //set up a slow consumer
+ session.createConsumer(destination).setMessageListener(this);
+ connection.start();
+
+ //create a publisher
+ MessageProducer producer = session.createProducer(destination);
+ Message msg = session.createTextMessage("Message");
+
+ //publish in bursts that are fast enough to cause channel flow control
+ for(int i = 0; i < 10; i++)
+ {
+ for(int j = 0; j < 100; j++)
+ {
+ producer.send(msg);
+ sent++;
+ }
+ waitUntilReceived(sent - 40);
+ }
+
+ waitUntilReceived(sent);
+
+ session.close();
+ connection.close();
+ }
+
+
+ private synchronized void waitUntilReceived(int count) throws InterruptedException
+ {
+ while(received <count)
+ {
+ wait();
+ }
+ }
+
+ public synchronized void onMessage(Message message)
+ {
+ try
+ {
+ Thread.sleep(50);
+
+ received++;
+ notify();
+ }
+ catch (InterruptedException e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ private static String randomize(String in)
+ {
+ return in + System.currentTimeMillis();
+ }
+
+ public static void main(String[] argv) throws Exception
+ {
+ new ChannelFlowTest(argv.length == 0 ? "localhost:5672" : argv[0]);
+ }
+
+}
diff --git a/Final/java/client/src/old_test/java/org/apache/qpid/fragmentation/TestLargePublisher.java b/Final/java/client/src/old_test/java/org/apache/qpid/fragmentation/TestLargePublisher.java
new file mode 100644
index 0000000000..a246352d8b
--- /dev/null
+++ b/Final/java/client/src/old_test/java/org/apache/qpid/fragmentation/TestLargePublisher.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.fragmentation;
+
+import org.apache.qpid.AMQException;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.exchange.ExchangeDefaults;
+import org.apache.qpid.url.URLSyntaxException;
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.client.AMQTopic;
+import org.apache.qpid.client.AMQSession;
+import org.apache.qpid.jms.MessageProducer;
+import org.apache.qpid.jms.Session;
+import org.apache.log4j.Logger;
+
+import javax.jms.BytesMessage;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageListener;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+/**
+ * A client that behaves as follows:
+ * <ul><li>Connects to a queue, whose name is specified as a cmd-line argument</li>
+ * <li>Creates a temporary queue</li>
+ * <li>Creates messages containing a property that is the name of the temporary queue</li>
+ * <li>Fires off a message on the original queue and waits for a response on the temporary queue</li>
+ * </ul>
+ */
+public class TestLargePublisher
+{
+ private static final Logger _log = Logger.getLogger(TestLargePublisher.class);
+
+ private AMQConnection _connection;
+
+ private AMQSession _session;
+
+ private class CallbackHandler implements MessageListener
+ {
+ private int _expectedMessageCount;
+
+ private int _actualMessageCount;
+
+ private long _startTime;
+
+ public CallbackHandler(int expectedMessageCount, long startTime)
+ {
+ _expectedMessageCount = expectedMessageCount;
+ _startTime = startTime;
+ }
+
+ public void onMessage(Message m)
+ {
+ if (_log.isDebugEnabled())
+ {
+ _log.debug("Message received: " + m);
+ }
+ _actualMessageCount++;
+ if (_actualMessageCount%1000 == 0)
+ {
+ _log.info("Received message count: " + _actualMessageCount);
+ }
+ /*if (!"henson".equals(m.toString()))
+ {
+ _log.error("AbstractJMSMessage response not correct: expected 'henson' but got " + m.toString());
+ }
+ else
+ {
+ if (_log.isDebugEnabled())
+ {
+ _log.debug("AbstractJMSMessage " + m + " received");
+ }
+ else
+ {
+ _log.info("AbstractJMSMessage received");
+ }
+ } */
+
+ if (_actualMessageCount == _expectedMessageCount)
+ {
+ long timeTaken = System.currentTimeMillis() - _startTime;
+ System.out.println("Total time taken to receive " + _expectedMessageCount+ " messages was " +
+ timeTaken + "ms, equivalent to " +
+ (_expectedMessageCount/(timeTaken/1000.0)) + " messages per second");
+ }
+ }
+ }
+
+ public TestLargePublisher(String host, int port, String clientID,
+ final int messageCount) throws AMQException,URLSyntaxException
+ {
+ try
+ {
+ createConnection(host, port, clientID);
+
+ _session = (AMQSession) _connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ AMQTopic destination = new AMQTopic(_session.getDefaultTopicExchangeName(), new AMQShortString("large"));
+ MessageProducer producer = (MessageProducer) _session.createProducer(destination);
+
+ _connection.start();
+ //TextMessage msg = _session.createTextMessage(tempDestination.getQueueName() + "/Presented to in conjunction with Mahnah Mahnah and the Snowths");
+ final long startTime = System.currentTimeMillis();
+
+ for (int i = 0; i < messageCount; i++)
+ {
+ BytesMessage msg = _session.createBytesMessage();
+ populateMessage(msg);
+ producer.send(msg);
+ }
+ _log.info("Finished sending " + messageCount + " messages");
+ }
+ catch (JMSException e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ private void createConnection(String host, int port, String clientID) throws AMQException , URLSyntaxException
+ {
+ _connection = new AMQConnection(host, port, "guest", "guest",
+ clientID, "/test");
+ }
+
+ private void populateMessage(BytesMessage msg) throws JMSException
+ {
+ int size = 1024 * 187; // 187k
+ byte[] data = new byte[size];
+ for (int i = 0; i < data.length; i++)
+ {
+ data[i] = (byte)(i%25);
+ }
+ msg.writeBytes(data);
+ }
+
+ /**
+ *
+ * @param args argument 1 if present specifies the name of the temporary queue to create. Leaving it blank
+ * means the server will allocate a name.
+ */
+ public static void main(String[] args) throws URLSyntaxException
+ {
+ final String host;
+ final int port;
+ final int numMessages;
+ if (args.length == 0)
+ {
+ host = "localhost";
+ port = 5672;
+ numMessages = 100;
+// System.err.println("Usage: TestLargePublisher <host> <port> <number of messages>");
+ }
+ else
+ {
+ host = args[0];
+ port = Integer.parseInt(args[1]);
+ numMessages = Integer.parseInt(args[2]);
+ }
+
+ try
+ {
+ InetAddress address = InetAddress.getLocalHost();
+ String clientID = address.getHostName() + System.currentTimeMillis();
+ TestLargePublisher client = new TestLargePublisher(host, port, clientID, numMessages);
+ }
+ catch (UnknownHostException e)
+ {
+ e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
+ }
+ catch (AMQException e)
+ {
+ System.err.println("Error in client: " + e);
+ e.printStackTrace();
+ }
+
+ //System.exit(0);
+ }
+}
diff --git a/Final/java/client/src/old_test/java/org/apache/qpid/fragmentation/TestLargeSubscriber.java b/Final/java/client/src/old_test/java/org/apache/qpid/fragmentation/TestLargeSubscriber.java
new file mode 100644
index 0000000000..b0cde22349
--- /dev/null
+++ b/Final/java/client/src/old_test/java/org/apache/qpid/fragmentation/TestLargeSubscriber.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.fragmentation;
+
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.client.AMQTopic;
+import org.apache.qpid.client.AMQSession;
+import org.apache.qpid.jms.Session;
+import org.apache.qpid.exchange.ExchangeDefaults;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.log4j.Logger;
+
+import javax.jms.*;
+import java.net.InetAddress;
+
+public class TestLargeSubscriber
+{
+ private static final Logger _logger = Logger.getLogger(TestLargeSubscriber.class);
+
+ private static MessageProducer _destinationProducer;
+
+ private static String _destinationName;
+
+ public static void main(String[] args)
+ {
+ _logger.info("Starting...");
+
+ final String host;
+ final int port;
+ final String username;
+ final String password;
+ final String virtualPath;
+ final int numExpectedMessages;
+ if (args.length == 0)
+ {
+ host = "localhost";
+ port = 5672;
+ username = "guest";
+ password = "guest";
+ virtualPath = "/test";
+ numExpectedMessages = 100;
+ }
+ else if (args.length == 6)
+ {
+ host = args[0];
+ port = Integer.parseInt(args[1]);
+ username = args[2];
+ password = args[3];
+ virtualPath = args[4];
+ numExpectedMessages = Integer.parseInt(args[5]);
+ }
+ else
+ {
+ System.out.println("Usage: host port username password virtual-path expectedMessageCount");
+ System.exit(1);
+ throw new RuntimeException("cannot be reached");
+ }
+
+ try
+ {
+ InetAddress address = InetAddress.getLocalHost();
+ AMQConnection con = new AMQConnection(host, port, username, password,
+ address.getHostName(), virtualPath);
+ final AMQSession session = (AMQSession) con.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ final int expectedMessageCount = numExpectedMessages;
+
+ MessageConsumer consumer = session.createConsumer(new AMQTopic(session.getDefaultTopicExchangeName(),
+ new AMQShortString("large")),
+ 100, true, false, null);
+
+ consumer.setMessageListener(new MessageListener()
+ {
+ private int _messageCount;
+
+ private long _startTime = 0;
+
+ public void onMessage(Message message)
+ {
+ validateMessage(message);
+ if (_messageCount++ == 0)
+ {
+ _startTime = System.currentTimeMillis();
+ }
+ if (_logger.isInfoEnabled())
+ {
+ _logger.info("Got message '" + message + "'");
+ }
+ if (_messageCount == expectedMessageCount)
+ {
+ long totalTime = System.currentTimeMillis() - _startTime;
+ _logger.error("Total time to receive " + _messageCount + " messages was " +
+ totalTime + "ms. Rate is " + (_messageCount/(totalTime/1000.0)));
+ }
+ }
+
+ private void validateMessage(Message message)
+ {
+ if (!(message instanceof BytesMessage))
+ {
+ _logger.error("Message is not of correct type - should be BytesMessage and is " +
+ message.getClass());
+ }
+ BytesMessage bm = (BytesMessage) message;
+ final int expectedSize = 1024 * 187; // 187k
+ try
+ {
+ if (bm.getBodyLength() != expectedSize)
+ {
+ _logger.error("Message is not correct length - should be " + expectedSize + " and is " +
+ bm.getBodyLength());
+ }
+ }
+ catch (JMSException e)
+ {
+ _logger.error("Failed to validate message: " + e, e);
+ }
+ try
+ {
+ byte[] data = new byte[(int)bm.getBodyLength()];
+ bm.readBytes(data);
+ for (int i = 0; i < data.length; i++)
+ {
+ if (data[i] != (byte)(i%25))
+ {
+ _logger.error("byte " + i + " of message is wrong - should be " + i%25 + " but is " +
+ data[i]);
+ }
+ }
+ _logger.info("***** Validated message successfully");
+ }
+ catch (JMSException e)
+ {
+ _logger.error("Failed to validate message: " + e, e);
+ }
+ }
+ });
+ con.start();
+ }
+ catch (Throwable t)
+ {
+ System.err.println("Fatal error: " + t);
+ t.printStackTrace();
+ }
+
+ System.out.println("Waiting...");
+ }
+}
+
diff --git a/Final/java/client/src/old_test/java/org/apache/qpid/headers/Listener.java b/Final/java/client/src/old_test/java/org/apache/qpid/headers/Listener.java
new file mode 100644
index 0000000000..cb5caefc1e
--- /dev/null
+++ b/Final/java/client/src/old_test/java/org/apache/qpid/headers/Listener.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.headers;
+
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.client.AMQSession;
+import org.apache.qpid.jms.Session;
+//import org.apache.qpid.testutil.Config;
+
+import javax.jms.MessageListener;
+import javax.jms.Message;
+import javax.jms.Destination;
+import javax.jms.MessageProducer;
+import javax.jms.JMSException;
+
+public class Listener //implements MessageListener
+{
+/* private final AMQConnection _connection;
+ private final MessageProducer _controller;
+ private final AMQSession _session;
+ private final MessageFactory _factory;
+ private int count;
+ private long start;
+
+ Listener(AMQConnection connection, Destination exchange) throws Exception
+ {
+ _connection = connection;
+ _session = (AMQSession) connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ _factory = new MessageFactory(_session, 0, 19);
+
+ //register for events
+ _factory.createConsumer(exchange).setMessageListener(this);
+ _connection.start();
+
+ _controller = _session.createProducer(exchange);
+ }
+
+ private void shutdown()
+ {
+ try
+ {
+ _session.close();
+ _connection.stop();
+ _connection.close();
+ }
+ catch(Exception e)
+ {
+ e.printStackTrace(System.out);
+ }
+ }
+
+ private void report()
+ {
+ try
+ {
+ String msg = getReport();
+ _controller.send(_factory.createReportResponseMessage(msg));
+ System.out.println("Sent report: " + msg);
+ }
+ catch(Exception e)
+ {
+ e.printStackTrace(System.out);
+ }
+ }
+
+ private String getReport() throws JMSException
+ {
+ long time = (System.currentTimeMillis() - start);
+ return "Received " + count + " in " + time + "ms";
+ }
+
+ public void onMessage(Message message)
+ {
+ if(count == 0) start = System.currentTimeMillis();
+
+ if(_factory.isShutdown(message))
+ {
+ shutdown();
+ }
+ else if(_factory.isReport(message))
+ {
+ //send a report:
+ report();
+ }
+ else if (++count % 100 == 0)
+ {
+ System.out.println("Received " + count + " messages.");
+ }
+ }
+
+ public static void main(String[] argv) throws Exception
+ {
+ Config config = new Config();
+ config.setType(Config.HEADERS);
+ config.setName("test_headers_exchange");
+ config.setOptions(argv);
+ new Listener((AMQConnection) config.getConnection(), config.getDestination());
+ }*/
+}
diff --git a/Final/java/client/src/old_test/java/org/apache/qpid/headers/MessageFactory.java b/Final/java/client/src/old_test/java/org/apache/qpid/headers/MessageFactory.java
new file mode 100644
index 0000000000..a2d575fdd4
--- /dev/null
+++ b/Final/java/client/src/old_test/java/org/apache/qpid/headers/MessageFactory.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.headers;
+
+import org.apache.qpid.client.AMQSession;
+import org.apache.qpid.framing.FieldTable;
+import org.apache.qpid.framing.FieldTableFactory;
+
+import javax.jms.BytesMessage;
+import javax.jms.Destination;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.TextMessage;
+
+/**
+ */
+class MessageFactory
+{
+ private static final char[] DATA = "abcdefghijklmnopqrstuvwxyz".toCharArray();
+
+ private final AMQSession _session;
+ private final byte[] _payload;
+
+ private String[] _headerNames;
+
+ MessageFactory(AMQSession session)
+ {
+ this(session, Integer.getInteger("amqj.test.message_size", 256).intValue(), 5);
+ }
+
+ MessageFactory(AMQSession session, int payloadSize, int headerCount)
+ {
+ if (headerCount < 1)
+ {
+ throw new IllegalArgumentException("Header count must be positive");
+ }
+ _session = session;
+ _payload = new byte[payloadSize];
+ for (int i = 0; i < _payload.length; i++)
+ {
+ _payload[i] = (byte) DATA[i % DATA.length];
+ }
+ _headerNames = new String[headerCount];
+ // note that with the standard encoding the headers get prefixed with an S to indicate their type
+ for (int i = 0; i < _headerNames.length; i++)
+ {
+ if (i < 10)
+ {
+ _headerNames[i] = "F000" + i;
+ }
+ else if (i >= 10 && i < 100)
+ {
+ _headerNames[i] = "F00" + i;
+ }
+ else
+ {
+ _headerNames[i] = "F0" + i;
+ }
+ }
+ }
+
+ Message createEventMessage() throws JMSException
+ {
+ BytesMessage msg = _session.createBytesMessage();
+ if (_payload.length != 0)
+ {
+ msg.writeBytes(_payload);
+ }
+ return setHeaders(msg, _headerNames);
+ }
+
+ Message createShutdownMessage() throws JMSException
+ {
+ return setHeaders(_session.createMessage(), new String[]{"F0000", "SHUTDOWN"});
+ }
+
+ Message createReportRequestMessage() throws JMSException
+ {
+ return setHeaders(_session.createMessage(), new String[]{"F0000", "REPORT"});
+ }
+
+ Message createReportResponseMessage(String msg) throws JMSException
+ {
+ return setHeaders(_session.createTextMessage(msg), new String[]{"CONTROL", "REPORT"});
+ }
+
+ boolean isShutdown(Message m)
+ {
+ return checkPresent(m, "SHUTDOWN");
+ }
+
+ boolean isReport(Message m)
+ {
+ return checkPresent(m, "REPORT");
+ }
+
+ Object getReport(Message m)
+ {
+ try
+ {
+ return ((TextMessage) m).getText();
+ }
+ catch (JMSException e)
+ {
+ e.printStackTrace(System.out);
+ return e.toString();
+ }
+ }
+
+ FieldTable getConsumerBinding()
+ {
+ FieldTable binding = FieldTableFactory.newFieldTable();
+ binding.setString("SF0000", "value");
+ return binding;
+ }
+
+ FieldTable getControllerBinding()
+ {
+ FieldTable binding = FieldTableFactory.newFieldTable();
+ binding.setString("SCONTROL", "value");
+ return binding;
+ }
+
+ MessageConsumer createConsumer(Destination source) throws Exception
+ {
+ return _session.createConsumer(source, 0, false, true, null, getConsumerBinding());
+ }
+
+ MessageConsumer createController(Destination source) throws Exception
+ {
+ return _session.createConsumer(source, 0, false, true, null, getControllerBinding());
+ }
+
+ private static boolean checkPresent(Message m, String s)
+ {
+ try
+ {
+ return m.getStringProperty(s) != null;
+ }
+ catch (JMSException e)
+ {
+ e.printStackTrace(System.out);
+ return false;
+ }
+ }
+
+ private static Message setHeaders(Message m, String[] headers) throws JMSException
+ {
+ for (int i = 0; i < headers.length; i++)
+ {
+ // the value in GRM is 5 bytes
+ m.setStringProperty(headers[i], "value");
+ }
+ return m;
+ }
+}
diff --git a/Final/java/client/src/old_test/java/org/apache/qpid/headers/Publisher.java b/Final/java/client/src/old_test/java/org/apache/qpid/headers/Publisher.java
new file mode 100644
index 0000000000..d9ef702c48
--- /dev/null
+++ b/Final/java/client/src/old_test/java/org/apache/qpid/headers/Publisher.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.headers;
+
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.client.AMQSession;
+//import org.apache.qpid.testutil.Config;
+
+import javax.jms.*;
+
+public class Publisher // implements MessageListener
+{
+/* private final Object _lock = new Object();
+ private final AMQConnection _connection;
+ private final AMQSession _session;
+ private final Destination _exchange;
+ private final MessageFactory _factory;
+ private final MessageProducer _publisher;
+ private int _count;
+
+ Publisher(AMQConnection connection, Destination exchange) throws Exception
+ {
+ _connection = connection;
+ _exchange = exchange;
+ _session = (AMQSession) _connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ _factory = new MessageFactory(_session, 0, 19);
+ _publisher = _session.createProducer(_exchange);
+ }
+
+ Publisher(Config config) throws Exception
+ {
+ this((AMQConnection) config.getConnection(), config.getDestination());
+ }
+
+ private void test(int msgCount, int consumerCount) throws Exception
+ {
+ _count = consumerCount;
+ _factory.createController(_exchange).setMessageListener(this);
+ _connection.start();
+ long start = System.currentTimeMillis();
+ publish(msgCount);
+ waitForCompletion(consumerCount);
+ long end = System.currentTimeMillis();
+
+ System.out.println("Completed in " + (end - start) + " ms.");
+
+ //request shutdown
+ _publisher.send(_factory.createShutdownMessage());
+
+ _connection.stop();
+ _connection.close();
+ }
+
+ private void publish(int count) throws Exception
+ {
+
+ //send events
+ for (int i = 0; i < count; i++)
+ {
+ _publisher.send(_factory.createEventMessage());
+ if ((i + 1) % 100 == 0)
+ {
+ System.out.println("Sent " + (i + 1) + " messages");
+ }
+ }
+
+ //request report
+ _publisher.send(_factory.createReportRequestMessage());
+ }
+
+ private void waitForCompletion(int consumers) throws Exception
+ {
+ System.out.println("Waiting for completion...");
+ synchronized (_lock)
+ {
+ while (_count > 0)
+ {
+ _lock.wait();
+ }
+ }
+ }
+
+
+ public void onMessage(Message message)
+ {
+ System.out.println("Received report " + _factory.getReport(message) + " " + --_count + " remaining");
+ if (_count == 0)
+ {
+ synchronized (_lock)
+ {
+ _lock.notify();
+ }
+ }
+ }
+
+
+ public static void main(String[] argv) throws Exception
+ {
+ if (argv.length >= 2)
+ {
+ int msgCount = Integer.parseInt(argv[argv.length - 2]);
+ int consumerCount = Integer.parseInt(argv[argv.length - 1]);
+
+ Config config = new Config();
+ config.setType(Config.HEADERS);
+ config.setName("test_headers_exchange");
+ String[] options = new String[argv.length - 2];
+ System.arraycopy(argv, 0, options, 0, options.length);
+ config.setOptions(options);
+
+ new Publisher(config).test(msgCount, consumerCount);
+ }
+
+ }*/
+}
diff --git a/Final/java/client/src/old_test/java/org/apache/qpid/jndi/referenceable/Bind.java b/Final/java/client/src/old_test/java/org/apache/qpid/jndi/referenceable/Bind.java
new file mode 100644
index 0000000000..ee6a12c233
--- /dev/null
+++ b/Final/java/client/src/old_test/java/org/apache/qpid/jndi/referenceable/Bind.java
@@ -0,0 +1,273 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.jndi.referenceable;
+
+import org.apache.qpid.client.*;
+import org.apache.qpid.AMQException;
+import org.apache.qpid.url.URLSyntaxException;
+
+import javax.jms.*;
+import javax.naming.*;
+
+import java.util.Properties;
+import java.io.InputStream;
+import java.io.FileInputStream;
+import java.io.IOException;
+
+/**
+ * Binds a reference from a JNDI source.
+ * Given a properties file with the JNDI information and a binding string.
+ */
+public class Bind
+{
+ private static final String USAGE="USAGE: java bind <JNDI Properties file> -cf <url> <binding> | -c <url> <binding> [-t <topic Name> <binding>] [-q <queue Name> <binding>]";
+ public Bind(String propertiesFile, String bindingURL, Referenceable reference) throws NameAlreadyBoundException, NoInitialContextException
+ {
+ // Set up the environment for creating the initial context
+ String qpid_home = System.getProperty("QPID_HOME");
+
+ if (qpid_home == null || qpid_home.equals(""))
+ {
+ System.out.println("QPID_HOME is not set");
+ System.exit(1);
+ }
+
+ if (qpid_home.charAt(qpid_home.length() - 1) != '/')
+ {
+ qpid_home += "/";
+ }
+
+ try
+ {
+ InputStream inputStream = new FileInputStream(qpid_home + propertiesFile);
+ Properties properties = new Properties();
+ properties.load(inputStream);
+
+ // Create the initial context
+ Context ctx = new InitialContext(properties);
+
+ // Perform the binds
+ ctx.bind(bindingURL, reference);
+
+ // Close the context when we're done
+ ctx.close();
+ }
+ catch (IOException ioe)
+ {
+ System.out.println("Unable to access properties file:" + propertiesFile + " Due to:" + ioe);
+ }
+ catch (NamingException e)
+ {
+ System.out.println("Operation failed: " + e);
+ if (e instanceof NameAlreadyBoundException)
+ {
+ throw (NameAlreadyBoundException) e;
+ }
+
+ if (e instanceof NoInitialContextException)
+ {
+ throw (NoInitialContextException) e;
+ }
+ }
+
+ }
+
+ private static String parse(String[] args, int index, String what, String type)
+ {
+ try
+ {
+ return args[index];
+ }
+ catch (IndexOutOfBoundsException ioobe)
+ {
+ System.out.println("ERROR: No " + what + " specified for " + type + ".");
+ System.out.println(USAGE);
+ System.exit(1);
+ }
+
+ // The path is either return normally or exception.. which calls system exit so keep the compiler happy
+ return "Never going to happen";
+ }
+
+
+ public static void main(String[] args) throws NameAlreadyBoundException, NoInitialContextException, URLSyntaxException, AMQException, JMSException
+ {
+
+
+ org.apache.log4j.Logger.getRootLogger().setLevel(org.apache.log4j.Level.OFF);
+
+// org.apache.log4j.Logger _logger = org.apache.log4j.Logger.getLogger(AMQConnection.class);
+// _logger.setLevel(org.apache.log4j.Level.OFF);
+
+ boolean exit = false;
+
+ String qpid_home = System.getProperty("QPID_HOME");
+
+ if (qpid_home == null || qpid_home.equals(""))
+ {
+ System.out.println("QPID_HOME is not set");
+ exit = true;
+ }
+
+ if (args.length <= 2)
+ {
+ System.out.println("At least a connection or connection factory must be requested to be bound.");
+ exit = true;
+ }
+ else
+ {
+ if ((args.length - 1) % 3 != 0)
+ {
+ System.out.println("Not all values have full details");
+ exit = true;
+ }
+ }
+ if (exit)
+ {
+ System.out.println(USAGE);
+ System.exit(1);
+ }
+
+ if (qpid_home.charAt(qpid_home.length() - 1) != '/')
+
+ {
+ qpid_home += "/";
+ }
+
+ AMQConnectionFactory cf = null;
+ AMQConnection c = null;
+ AMQSession session = null;
+ Referenceable reference = null;
+
+ for (int index = 1; index < args.length; index ++)
+ {
+ String obj = args[index];
+
+ String what = "Invalid";
+ String binding;
+
+ if (obj.startsWith("-c"))
+ {
+ boolean isFactory = obj.contains("f");
+
+
+ if (isFactory)
+ {
+ what = "ConnectionFactory";
+ }
+ else
+ {
+ what = "Factory";
+ }
+
+ String url = parse(args, ++index, "url", what);
+
+ if (isFactory)
+ {
+
+ cf = new AMQConnectionFactory(url);
+ reference = cf;
+ }
+ else
+ {
+ c = new AMQConnection(url);
+ reference = c;
+ }
+
+ }
+
+ if (obj.equals("-t") || obj.equals("-q"))
+ {
+ if (c == null)
+ {
+ c = (AMQConnection) cf.createConnection();
+ }
+
+ if (session == null)
+ {
+ session = (AMQSession) c.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ }
+
+ }
+
+ if (obj.equals("-t"))
+ {
+
+ String topicName = parse(args, ++index, "Topic Name", "Topic");
+ reference = (AMQTopic) session.createTopic(topicName);
+ what = "Topic";
+ }
+ else
+ {
+ if (obj.equals("-q"))
+ {
+ String topicName = parse(args, ++index, "Queue Name", "Queue");
+ reference = (AMQQueue) session.createQueue(topicName);
+ what = "Queue";
+ }
+ }
+
+ binding = parse(args, ++index, "binding", what);
+ if (binding == null)
+ {
+ System.out.println(obj + " is not a known Object to bind.");
+ System.exit(1);
+ }
+ else
+ {
+ System.out.print("Binding:" + reference + " to " + binding);
+ try
+ {
+ new Bind(args[0], binding, reference);
+ System.out.println(" ..Successful");
+
+ }
+ catch (NameAlreadyBoundException nabe)
+ {
+ System.out.println("");
+ if (!obj.startsWith("-c") || index == args.length - 1)
+ {
+ throw nabe;
+ }
+ else
+ {
+ System.out.println("Continuing with other bindings using the same connection details");
+ }
+ }
+ finally
+ {
+ if (!obj.startsWith("-c") || index == args.length - 1)
+ {
+ if (c != null)
+ {
+ c.close();
+ }
+ }
+ }
+ }
+ }
+
+ if (c != null)
+ {
+ c.close();
+ }
+ }
+}
diff --git a/Final/java/client/src/old_test/java/org/apache/qpid/jndi/referenceable/Lookup.java b/Final/java/client/src/old_test/java/org/apache/qpid/jndi/referenceable/Lookup.java
new file mode 100644
index 0000000000..1c9d8b0fd5
--- /dev/null
+++ b/Final/java/client/src/old_test/java/org/apache/qpid/jndi/referenceable/Lookup.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.jndi.referenceable;
+
+import javax.jms.Connection;
+import javax.jms.JMSException;
+import javax.naming.Context;
+import javax.naming.InitialContext;
+import javax.naming.NamingException;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Properties;
+
+/**
+ * Looksup a reference from a JNDI source.
+ * Given a properties file with the JNDI information and a binding string.
+ */
+public class Lookup
+{
+ private static final String USAGE = "USAGE: java lookup <JNDI Properties file> -b <binding>";
+ private Properties _properties;
+ private Object _object;
+
+ public Lookup(String propertiesFile, String bindingValue) throws NamingException
+ {
+ // Set up the environment for creating the initial context
+ String qpid_home = System.getProperty("QPID_HOME");
+
+ if (qpid_home == null || qpid_home.equals(""))
+ {
+ System.out.println("QPID_HOME is not set");
+ System.exit(1);
+ }
+
+ if (qpid_home.charAt(qpid_home.length() - 1) != '/')
+ {
+ qpid_home += "/";
+ }
+
+ try
+ {
+ InputStream inputStream = new FileInputStream(qpid_home + propertiesFile);
+ Properties properties = new Properties();
+ properties.load(inputStream);
+
+ _properties = properties;
+ lookup(bindingValue);
+ }
+ catch (IOException ioe)
+ {
+ System.out.println("Unable to access properties file:" + propertiesFile + " Due to:" + ioe);
+ }
+ }
+
+ public Object lookup(String bindingValue) throws NamingException
+ {
+
+ // Create the initial context
+ Context ctx = new InitialContext(_properties);
+
+ // Perform the binds
+ _object = ctx.lookup(bindingValue);
+
+ // Close the context when we're done
+ ctx.close();
+
+ return getObject();
+ }
+
+ public Object getObject()
+ {
+ return _object;
+ }
+
+ private static String parse(String[] args, int index, String what)
+ {
+ try
+ {
+ return args[index];
+ }
+ catch (IndexOutOfBoundsException ioobe)
+ {
+ System.out.println("ERROR: No " + what + " specified.");
+ System.out.println(USAGE);
+ System.exit(1);
+ }
+
+ // The path is either return normally or exception.. which calls system exit so keep the compiler happy
+ return "Never going to happen";
+ }
+
+
+ public static void main(String[] args) throws NamingException
+ {
+ boolean exit = false;
+
+ String qpid_home = System.getProperty("QPID_HOME");
+
+ if (qpid_home == null || qpid_home.equals(""))
+ {
+ System.out.println("QPID_HOME is not set");
+ exit = true;
+ }
+
+ if (args.length <= 2)
+ {
+ System.out.println("At least a connection or connection factory must be requested to be bound.");
+ exit = true;
+ }
+ else
+ {
+ if ((args.length - 1) % 2 != 0)
+ {
+ System.out.println("Not all values have full details");
+ exit = true;
+ }
+ }
+ if (exit)
+ {
+ System.out.println(USAGE);
+ System.exit(1);
+ }
+
+ if (qpid_home.charAt(qpid_home.length() - 1) != '/')
+
+ {
+ qpid_home += "/";
+ }
+
+ for (int index = 1; index < args.length; index ++)
+ {
+ String obj = args[index];
+
+
+ if (obj.equals("-b"))
+ {
+ String binding = parse(args, ++index, "binding");
+
+ if (binding == null)
+ {
+ System.out.println("Binding not specified.");
+ System.exit(1);
+ }
+ else
+ {
+ System.out.print("Looking up:" + binding);
+ try
+ {
+ Lookup l = new Lookup(args[0], binding);
+
+ Object object = l.getObject();
+
+ if (object instanceof Connection)
+ {
+ try
+ {
+ ((Connection) object).close();
+ }
+ catch (JMSException jmse)
+ {
+ ;
+ }
+ }
+ }
+ catch (NamingException nabe)
+ {
+ System.out.println("Problem unbinding " + binding + " continuing with other values.");
+ }
+ }
+ }// if -b
+ else
+ {
+ System.out.println("Continuing with other bindings option not known:" + obj);
+ }
+ }//for
+ }//main
+}//class
diff --git a/Final/java/client/src/old_test/java/org/apache/qpid/jndi/referenceable/Unbind.java b/Final/java/client/src/old_test/java/org/apache/qpid/jndi/referenceable/Unbind.java
new file mode 100644
index 0000000000..1acead674c
--- /dev/null
+++ b/Final/java/client/src/old_test/java/org/apache/qpid/jndi/referenceable/Unbind.java
@@ -0,0 +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.
+ *
+ */
+package org.apache.qpid.jndi.referenceable;
+
+import javax.naming.*;
+
+import java.util.Properties;
+import java.io.InputStream;
+import java.io.FileInputStream;
+import java.io.IOException;
+
+/**
+ * Unbinds a reference from a JNDI source.
+ * Given a properties file with the JNDI information and a binding string.
+ */
+public class Unbind
+{
+ private static final String USAGE = "USAGE: java unbind <JNDI Properties file> -b <binding>";
+
+ public Unbind(String propertiesFile, String bindingValue) throws NamingException
+ {
+ // Set up the environment for creating the initial context
+ String qpid_home = System.getProperty("QPID_HOME");
+
+ if (qpid_home == null || qpid_home.equals(""))
+ {
+ System.out.println("QPID_HOME is not set");
+ System.exit(1);
+ }
+
+ if (qpid_home.charAt(qpid_home.length() - 1) != '/')
+ {
+ qpid_home += "/";
+ }
+
+ try
+ {
+ InputStream inputStream = new FileInputStream(qpid_home + propertiesFile);
+ Properties properties = new Properties();
+ properties.load(inputStream);
+
+ // Create the initial context
+ Context ctx = new InitialContext(properties);
+
+ // Perform the binds
+ ctx.unbind(bindingValue);
+
+ // Close the context when we're done
+ ctx.close();
+ }
+ catch (IOException ioe)
+ {
+ System.out.println("Unable to access properties file:" + propertiesFile + " Due to:" + ioe);
+ }
+ }
+
+ private static String parse(String[] args, int index, String what)
+ {
+ try
+ {
+ return args[index];
+ }
+ catch (IndexOutOfBoundsException ioobe)
+ {
+ System.out.println("ERROR: No " + what + " specified.");
+ System.out.println(USAGE);
+ System.exit(1);
+ }
+
+ // The path is either return normally or exception.. which calls system exit so keep the compiler happy
+ return "Never going to happen";
+ }
+
+
+ public static void main(String[] args) throws NamingException
+ {
+ boolean exit = false;
+
+ String qpid_home = System.getProperty("QPID_HOME");
+
+ if (qpid_home == null || qpid_home.equals(""))
+ {
+ System.out.println("QPID_HOME is not set");
+ exit = true;
+ }
+
+ if (args.length <= 2)
+ {
+ System.out.println("At least a connection or connection factory must be requested to be bound.");
+ exit = true;
+ }
+ else
+ {
+ if ((args.length - 1) % 2 != 0)
+ {
+ System.out.println("Not all values have full details");
+ exit = true;
+ }
+ }
+ if (exit)
+ {
+ System.out.println(USAGE);
+ System.exit(1);
+ }
+
+ if (qpid_home.charAt(qpid_home.length() - 1) != '/')
+
+ {
+ qpid_home += "/";
+ }
+
+ for (int index = 1; index < args.length; index ++)
+ {
+ String obj = args[index];
+
+
+ if (obj.equals("-b"))
+ {
+ String binding = parse(args, ++index, "binding");
+
+ if (binding == null)
+ {
+ System.out.println("Binding not specified.");
+ System.exit(1);
+ }
+ else
+ {
+ System.out.print("UnBinding:" + binding);
+ try
+ {
+ new Unbind(args[0], binding);
+ System.out.println(" ..Successful");
+ }
+ catch (NamingException nabe)
+ {
+ System.out.println("");
+
+ System.out.println("Problem unbinding " + binding + " continuing with other values.");
+ }
+ }
+ }// if -b
+ else
+ {
+ System.out.println("Continuing with other bindings option not known:" + obj);
+ }
+ }//for
+ }//main
+}//class
diff --git a/Final/java/client/src/old_test/java/org/apache/qpid/latency/LatencyTest.java b/Final/java/client/src/old_test/java/org/apache/qpid/latency/LatencyTest.java
new file mode 100644
index 0000000000..4865a68dc4
--- /dev/null
+++ b/Final/java/client/src/old_test/java/org/apache/qpid/latency/LatencyTest.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.latency;
+
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.client.AMQQueue;
+import org.apache.qpid.client.AMQDestination;
+import org.apache.qpid.client.AMQSession;
+import org.apache.qpid.exchange.ExchangeDefaults;
+import org.apache.qpid.framing.AMQShortString;
+
+import javax.jms.MessageProducer;
+import javax.jms.Message;
+import javax.jms.MessageListener;
+import javax.jms.JMSException;
+import javax.jms.TextMessage;
+import javax.jms.BytesMessage;
+
+public class LatencyTest implements MessageListener
+{
+ private volatile boolean waiting;
+ private int sent;
+ private int received;
+
+ private final byte[] data;
+
+ private long min = Long.MAX_VALUE;
+ private long max = 0;
+ private long total = 0;
+
+ LatencyTest(String broker, int count, int delay, int length) throws Exception
+ {
+ this(new AMQConnection(broker, "guest", "guest", randomize("Client"), "/test"), count, delay, length);
+ }
+
+ LatencyTest(AMQConnection connection, int count, int delay, int length) throws Exception
+ {
+ this(connection, new AMQQueue(connection.getDefaultQueueExchangeName(), new AMQShortString(randomize("LatencyTest")), true), count, delay, length);
+ }
+
+ LatencyTest(AMQConnection connection, AMQDestination destination, int count, int delay, int length) throws Exception
+ {
+ AMQSession session = (AMQSession) connection.createSession(false, AMQSession.NO_ACKNOWLEDGE);
+
+ data = new byte[length];
+ for(int i = 0; i < data.length; i++)
+ {
+ data[i] = (byte) (i % 100);
+ }
+
+ //set up a consumer
+ session.createConsumer(destination).setMessageListener(this);
+ connection.start();
+
+ //create a publisher
+ MessageProducer producer = session.createProducer(destination, false, false, true);
+
+ //publish at a low volume
+ for(int i = 0; i < count; i++)
+ {
+ BytesMessage msg = session.createBytesMessage();
+ msg.writeBytes(data);
+ msg.setStringProperty("sent-at", Long.toString(System.nanoTime()));
+ producer.send(msg);
+ Thread.sleep(delay);
+ if(++sent % 100 == 0)
+ {
+ System.out.println("Sent " + sent + " of " + count);
+ }
+ }
+
+ waitUntilReceived(sent);
+
+ session.close();
+ connection.close();
+
+ System.out.println("Latency (in nanoseconds): avg=" + (total/sent) + ", min=" + min + ", max=" + max
+ + ", avg(discarding min and max)=" + ((total - min - max) / (sent - 2)));
+ }
+
+
+ private synchronized void waitUntilReceived(int count) throws InterruptedException
+ {
+ waiting = true;
+ while(received < count)
+ {
+ wait();
+ }
+ waiting = false;
+ }
+
+ public void onMessage(Message message)
+ {
+ received++;
+ try
+ {
+ long sent = Long.parseLong(message.getStringProperty("sent-at"));
+ long time = System.nanoTime() - sent;
+ total += time;
+ min = Math.min(min, time);
+ max = Math.max(max, time);
+ }
+ catch (JMSException e)
+ {
+ e.printStackTrace();
+ }
+
+ if(waiting){
+ synchronized(this)
+ {
+ notify();
+ }
+ }
+ }
+
+ private static String randomize(String in)
+ {
+ return in + System.currentTimeMillis();
+ }
+
+ public static void main(String[] argv) throws Exception
+ {
+ String host = argv.length > 0 ? argv[0] : "localhost:5672";
+ if("-help".equals(host))
+ {
+ System.out.println("Usage: <broker> <message count> <delay between messages> <message size>");
+ }
+ int count = argv.length > 1 ? Integer.parseInt(argv[1]) : 1000;
+ int delay = argv.length > 2 ? Integer.parseInt(argv[2]) : 1000;
+ int size = argv.length > 3 ? Integer.parseInt(argv[3]) : 512;
+ new LatencyTest(host, count, delay, size);
+ }
+
+
+}
diff --git a/Final/java/client/src/old_test/java/org/apache/qpid/mina/AcceptorTest.java b/Final/java/client/src/old_test/java/org/apache/qpid/mina/AcceptorTest.java
new file mode 100644
index 0000000000..f0ac0e6902
--- /dev/null
+++ b/Final/java/client/src/old_test/java/org/apache/qpid/mina/AcceptorTest.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.mina;
+
+import org.apache.log4j.Logger;
+import org.apache.mina.common.ByteBuffer;
+import org.apache.mina.common.IoAcceptor;
+import org.apache.mina.common.IoHandlerAdapter;
+import org.apache.mina.common.IoSession;
+import org.apache.mina.transport.socket.nio.SocketAcceptor;
+import org.apache.mina.transport.socket.nio.SocketAcceptorConfig;
+import org.apache.mina.transport.socket.nio.SocketSessionConfig;
+import org.apache.qpid.pool.ReadWriteThreadModel;
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+
+import junit.framework.TestCase;
+
+/**
+ * Tests MINA socket performance. This acceptor simply reads data from the network and writes it back again.
+ *
+ */
+public class AcceptorTest extends TestCase
+{
+ private static final Logger _logger = Logger.getLogger(AcceptorTest.class);
+
+ public static int PORT = 9999;
+
+ private static class TestHandler extends IoHandlerAdapter
+ {
+ private int _sentCount;
+
+ private int _bytesSent;
+
+ public void messageReceived(IoSession session, Object message) throws Exception
+ {
+ ((ByteBuffer) message).acquire();
+ session.write(message);
+ _logger.debug("Sent response " + ++_sentCount);
+ _bytesSent += ((ByteBuffer)message).remaining();
+ _logger.debug("Bytes sent: " + _bytesSent);
+ }
+
+ public void messageSent(IoSession session, Object message) throws Exception
+ {
+ //((ByteBuffer) message).release();
+ }
+
+ public void exceptionCaught(IoSession session, Throwable cause) throws Exception
+ {
+ _logger.error("Error: " + cause, cause);
+ }
+ }
+
+ public void testStartAcceptor() throws IOException
+ {
+ IoAcceptor acceptor = null;
+ acceptor = new SocketAcceptor();
+
+ SocketAcceptorConfig config = (SocketAcceptorConfig) acceptor.getDefaultConfig();
+ SocketSessionConfig sc = (SocketSessionConfig) config.getSessionConfig();
+ sc.setTcpNoDelay(true);
+ sc.setSendBufferSize(32768);
+ sc.setReceiveBufferSize(32768);
+
+ config.setThreadModel(ReadWriteThreadModel.getInstance());
+
+ acceptor.bind(new InetSocketAddress(PORT),
+ new TestHandler());
+ _logger.info("Bound on port " + PORT);
+ }
+
+ public static void main(String[] args) throws IOException
+ {
+ AcceptorTest a = new AcceptorTest();
+ a.testStartAcceptor();
+ }
+
+ public static junit.framework.Test suite()
+ {
+ return new junit.framework.TestSuite(AcceptorTest.class);
+ }
+}
diff --git a/Final/java/client/src/old_test/java/org/apache/qpid/mina/BlockingAcceptorTest.java b/Final/java/client/src/old_test/java/org/apache/qpid/mina/BlockingAcceptorTest.java
new file mode 100644
index 0000000000..bfe29c47e6
--- /dev/null
+++ b/Final/java/client/src/old_test/java/org/apache/qpid/mina/BlockingAcceptorTest.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.mina;
+
+import org.apache.log4j.Logger;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.ServerSocket;
+import java.net.Socket;
+
+import junit.framework.TestCase;
+
+public class BlockingAcceptorTest extends TestCase
+{
+ private static final Logger _logger = Logger.getLogger(BlockingAcceptorTest.class);
+
+ public static int PORT = 9999;
+
+ public void testStartAcceptor() throws IOException
+ {
+
+ ServerSocket sock = new ServerSocket(PORT);
+
+ sock.setReuseAddress(true);
+ sock.setReceiveBufferSize(32768);
+ _logger.info("Bound on port " + PORT);
+
+ while (true)
+ {
+ final Socket s = sock.accept();
+ _logger.info("Received connection from " + s.getRemoteSocketAddress());
+ s.setReceiveBufferSize(32768);
+ s.setSendBufferSize(32768);
+ s.setTcpNoDelay(true);
+ new Thread(new Runnable()
+ {
+ public void run()
+ {
+ byte[] chunk = new byte[32768];
+ try
+ {
+ InputStream is = s.getInputStream();
+ OutputStream os = s.getOutputStream();
+
+ while (true)
+ {
+ int count = is.read(chunk, 0, chunk.length);
+ if (count > 0)
+ {
+ os.write(chunk, 0, count);
+ }
+ }
+ }
+ catch (IOException e)
+ {
+ _logger.error("Error - closing connection: " + e, e);
+ }
+ }
+ }, "SocketReaderWriter").start();
+ }
+ }
+
+ public static void main(String[] args) throws IOException
+ {
+ BlockingAcceptorTest a = new BlockingAcceptorTest();
+ a.testStartAcceptor();
+ }
+
+ public static junit.framework.Test suite()
+ {
+ return new junit.framework.TestSuite(AcceptorTest.class);
+ }
+}
diff --git a/Final/java/client/src/old_test/java/org/apache/qpid/mina/WriterTest.java b/Final/java/client/src/old_test/java/org/apache/qpid/mina/WriterTest.java
new file mode 100644
index 0000000000..910345624f
--- /dev/null
+++ b/Final/java/client/src/old_test/java/org/apache/qpid/mina/WriterTest.java
@@ -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.
+ *
+ */
+package org.apache.qpid.mina;
+
+import org.apache.log4j.Logger;
+import org.apache.mina.common.*;
+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 java.io.IOException;
+import java.net.InetSocketAddress;
+import java.util.concurrent.CountDownLatch;
+
+import junit.framework.TestCase;
+
+public class WriterTest extends TestCase
+{
+ private static final Logger _logger = Logger.getLogger(WriterTest.class);
+
+ private static class RunnableWriterTest implements Runnable
+ {
+ private Logger _logger;
+
+ private IoSession _session;
+
+ private long _startTime;
+
+ private long[] _chunkTimes;
+
+ private int _chunkCount = 500000;
+
+ private int _chunkSize = 1024;
+
+ private CountDownLatch _notifier;
+
+ public RunnableWriterTest(Logger logger)
+ {
+ _logger = logger;
+ }
+
+ public void run()
+ {
+ _startTime = System.currentTimeMillis();
+ _notifier = new CountDownLatch(1);
+ for (int i = 0; i < _chunkCount; i++)
+ {
+ ByteBuffer buf = ByteBuffer.allocate(_chunkSize, false);
+ byte check = (byte) (i % 128);
+ buf.put(check);
+ buf.fill((byte)88, buf.remaining());
+ buf.flip();
+ _session.write(buf);
+ }
+
+ try
+ {
+ _logger.info("All buffers sent; waiting for receipt from server");
+ _notifier.await();
+ }
+ catch (InterruptedException e)
+ {
+ }
+ _logger.info("Completed");
+ long totalTime = System.currentTimeMillis() - _startTime;
+ _logger.info("Total time: " + totalTime);
+ _logger.info("MB per second: " + (_chunkSize * _chunkCount)/totalTime);
+ long lastChunkTime = _startTime;
+ double average = 0;
+ for (int i = 0; i < _chunkTimes.length; i++)
+ {
+ if (i == 0)
+ {
+ average = _chunkTimes[i] - _startTime;
+ }
+ else
+ {
+ long delta = _chunkTimes[i] - lastChunkTime;
+ if (delta != 0)
+ {
+ average = (average + delta)/2;
+ }
+ }
+ lastChunkTime = _chunkTimes[i];
+ }
+ _logger.info("Average chunk time: " + average + "ms");
+ CloseFuture cf = _session.close();
+ cf.join();
+ }
+
+ private class WriterHandler extends IoHandlerAdapter
+ {
+ private int _chunksReceived = 0;
+
+ private int _partialBytesRead = 0;
+
+ private byte _partialCheckNumber;
+
+ private int _totalBytesReceived = 0;
+
+ public void messageReceived(IoSession session, Object message) throws Exception
+ {
+ ByteBuffer result = (ByteBuffer) message;
+ _totalBytesReceived += result.remaining();
+ int size = result.remaining();
+ long now = System.currentTimeMillis();
+ if (_partialBytesRead > 0)
+ {
+ int offset = _chunkSize - _partialBytesRead;
+ if (size >= offset)
+ {
+ _chunkTimes[_chunksReceived++] = now;
+ result.position(offset);
+ }
+ else
+ {
+ // have not read even one chunk, including the previous partial bytes
+ _partialBytesRead += size;
+ return;
+ }
+ }
+
+ int chunkCount = result.remaining()/_chunkSize;
+
+ for (int i = 0; i < chunkCount; i++)
+ {
+ _chunkTimes[_chunksReceived++] = now;
+ byte check = result.get();
+ _logger.debug("Check number " + check + " read");
+ if (check != (byte)((_chunksReceived - 1)%128))
+ {
+ _logger.error("Check number " + check + " read when expected " + (_chunksReceived%128));
+ }
+ _logger.debug("Chunk times recorded");
+
+ try
+ {
+ result.skip(_chunkSize - 1);
+ }
+ catch (IllegalArgumentException e)
+ {
+ _logger.error("Position was: " + result.position());
+ _logger.error("Tried to skip to: " + (_chunkSize * i));
+ _logger.error("limit was; " + result.limit());
+ }
+ }
+ _logger.debug("Chunks received now " + _chunksReceived);
+ _logger.debug("Bytes received: " + _totalBytesReceived);
+ _partialBytesRead = result.remaining();
+
+ if (_partialBytesRead > 0)
+ {
+ _partialCheckNumber = result.get();
+ }
+
+ if (_chunksReceived >= _chunkCount)
+ {
+ _notifier.countDown();
+ }
+
+ }
+
+ public void exceptionCaught(IoSession session, Throwable cause) throws Exception
+ {
+ _logger.error("Error: " + cause, cause);
+ }
+ }
+
+ public void startWriter(int chunkSize) throws IOException, InterruptedException
+ {
+ _chunkSize = chunkSize;
+
+ IoConnector ioConnector = null;
+
+ ioConnector = new SocketConnector();
+
+ SocketConnectorConfig cfg = (SocketConnectorConfig) ioConnector.getDefaultConfig();
+ cfg.setThreadModel(ThreadModel.MANUAL);
+ SocketSessionConfig scfg = (SocketSessionConfig) cfg.getSessionConfig();
+ scfg.setTcpNoDelay(true);
+ scfg.setSendBufferSize(32768);
+ scfg.setReceiveBufferSize(32768);
+
+ final InetSocketAddress address = new InetSocketAddress("localhost", AcceptorTest.PORT);
+ _logger.info("Attempting connection to " + address);
+ ConnectFuture future = ioConnector.connect(address, new WriterHandler());
+ // wait for connection to complete
+ future.join();
+ _logger.info("Connection completed");
+ // we call getSession which throws an IOException if there has been an error connecting
+ _session = future.getSession();
+ _chunkTimes = new long[_chunkCount];
+ Thread t = new Thread(this);
+ t.start();
+ t.join();
+ _logger.info("Test completed");
+ }
+ }
+
+ private RunnableWriterTest _runnableWriterTest = new RunnableWriterTest(_logger);
+
+ public void test1k() throws IOException, InterruptedException
+ {
+ _logger.info("Starting 1k test");
+ _runnableWriterTest.startWriter(1024);
+ }
+
+ public void test2k() throws IOException, InterruptedException
+ {
+ _logger.info("Starting 2k test");
+ _runnableWriterTest.startWriter(2048);
+ }
+
+ public void test4k() throws IOException, InterruptedException
+ {
+ _logger.info("Starting 4k test");
+ _runnableWriterTest.startWriter(4096);
+ }
+
+ public void test8k() throws IOException, InterruptedException
+ {
+ _logger.info("Starting 8k test");
+ _runnableWriterTest.startWriter(8192);
+ }
+
+ public void test16k() throws IOException, InterruptedException
+ {
+ _logger.info("Starting 16k test");
+ _runnableWriterTest.startWriter(16384);
+ }
+
+ public void test32k() throws IOException, InterruptedException
+ {
+ _logger.info("Starting 32k test");
+ _runnableWriterTest.startWriter(32768);
+ }
+
+ public static void main(String[] args) throws IOException, InterruptedException
+ {
+ WriterTest w = new WriterTest();
+ //w.test1k();
+ //w.test2k();
+ //w.test4k();
+ w.test8k();
+ //w.test16k();
+ //w.test32k();
+ }
+
+ public static junit.framework.Test suite()
+ {
+ return new junit.framework.TestSuite(WriterTest.class);
+ }
+}
diff --git a/Final/java/client/src/old_test/java/org/apache/qpid/multiconsumer/AMQTest.java b/Final/java/client/src/old_test/java/org/apache/qpid/multiconsumer/AMQTest.java
new file mode 100644
index 0000000000..db02b9954a
--- /dev/null
+++ b/Final/java/client/src/old_test/java/org/apache/qpid/multiconsumer/AMQTest.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.multiconsumer;
+
+import java.io.ByteArrayOutputStream;
+import java.util.zip.Deflater;
+import java.util.zip.Inflater;
+
+import javax.jms.Connection;
+import javax.jms.ExceptionListener;
+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 javax.jms.Topic;
+
+import junit.framework.TestCase;
+
+import org.apache.commons.codec.binary.Base64;
+import org.apache.qpid.client.AMQConnectionFactory;
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.client.AMQTopic;
+import org.apache.qpid.exchange.ExchangeDefaults;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.jms.Session;
+
+/**
+ * Test AMQ.
+ */
+public class AMQTest extends TestCase implements ExceptionListener
+{
+
+ private final static String COMPRESSION_PROPNAME = "_MSGAPI_COMP";
+ private final static String UTF8 = "UTF-8";
+ private static final String SUBJECT = "test.amq";
+ private static final String DUMMYCONTENT = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ private static final String HUGECONTENT;
+
+ private AMQConnection connect = null;
+ private Session pubSession = null;
+ private Session subSession = null;
+ private Topic topic = null;
+
+ static
+ {
+ StringBuilder sb = new StringBuilder(DUMMYCONTENT.length() * 115);
+ for (int i = 0; i < 100; i++)
+ {
+ sb.append(DUMMYCONTENT);
+ }
+ HUGECONTENT = sb.toString();
+ }
+
+ private void setup() throws Exception
+ {
+ connect = new AMQConnection("localhost", 5672, "guest", "guest", "client1", "/");
+ connect.setExceptionListener(this);
+ pubSession = connect.createSession(false, javax.jms.Session.AUTO_ACKNOWLEDGE);
+ subSession = connect.createSession(false, javax.jms.Session.AUTO_ACKNOWLEDGE);
+ topic = new AMQTopic(pubSession.getDefaultTopicExchangeName(), new AMQShortString(SUBJECT));
+
+ connect.start();
+ }
+
+ public void testMultipleListeners() throws Exception
+ {
+ setup();
+ try
+ {
+ // Create 5 listeners
+ MsgHandler[] listeners = new MsgHandler[5];
+ for (int i = 0; i < listeners.length; i++)
+ {
+ listeners[i] = new MsgHandler();
+ MessageConsumer subscriber = subSession.createConsumer(topic);
+ subscriber.setMessageListener(listeners[i]);
+ }
+ MessageProducer publisher = pubSession.createProducer(topic);
+ // Send a single message
+ TextMessage msg = pubSession.createTextMessage();
+ msg.setText(DUMMYCONTENT);
+ publisher.send(msg);
+ Thread.sleep(5000);
+ // Check listeners to ensure they all got it
+ for (int i = 0; i < listeners.length; i++)
+ {
+ if (listeners[i].isGotIt())
+ {
+ System.out.println("Got callback for listener " + i);
+ }
+ else
+ {
+ TestCase.fail("Listener " + i + " did not get callback");
+ }
+ }
+ }
+ catch (Throwable e)
+ {
+ System.err.println("Error: " + e);
+ e.printStackTrace(System.err);
+ }
+ finally
+ {
+ close();
+ }
+ }
+
+ public void testCompression() throws Exception
+ {
+ setup();
+ String comp = this.compressString(HUGECONTENT);
+ try
+ {
+ MsgHandler listener = new MsgHandler();
+ MessageConsumer subscriber = subSession.createConsumer(topic);
+ subscriber.setMessageListener(listener);
+ MessageProducer publisher = pubSession.createProducer(topic);
+
+ // Send a single message
+ TextMessage msg = pubSession.createTextMessage();
+ // Set the compressed text
+ msg.setText(comp);
+ msg.setBooleanProperty(COMPRESSION_PROPNAME, true);
+ publisher.send(msg);
+ Thread.sleep(1000);
+ // Check listeners to ensure we got it
+ if (listener.isGotIt())
+ {
+ System.out.println("Got callback for listener");
+ }
+ else
+ {
+ TestCase.fail("Listener did not get callback");
+ }
+ }
+ finally
+ {
+ close();
+ }
+ }
+
+ private void close() throws Exception
+ {
+ if (connect != null)
+ {
+ connect.close();
+ }
+ }
+
+ private class MsgHandler implements MessageListener
+ {
+ private boolean gotIt = false;
+
+ public void onMessage(Message msg)
+ {
+ try
+ {
+ TextMessage textMessage = (TextMessage) msg;
+ String string = textMessage.getText();
+ if (string != null && string.length() > 0)
+ {
+ gotIt = true;
+ }
+ if (textMessage.getBooleanProperty(COMPRESSION_PROPNAME))
+ {
+ string = inflateString(string);
+ }
+ System.out.println("Got callback of size " + (string==null?0:string.length()));
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ public boolean isGotIt()
+ {
+ return this.gotIt;
+ }
+ }
+
+ private String compressString(String string) throws Exception
+ {
+ long start = System.currentTimeMillis();
+ byte[] input = string.getBytes();
+ Deflater compressor = new Deflater(Deflater.BEST_COMPRESSION);
+ compressor.setInput(input);
+ compressor.finish();
+
+ // Get byte array from output of compressor
+ ByteArrayOutputStream baos = new ByteArrayOutputStream(input.length);
+ byte[] buf = new byte[1024];
+ while (!compressor.finished())
+ {
+ int cnt = compressor.deflate(buf);
+ baos.write(buf, 0, cnt);
+ }
+ baos.close();
+ byte[] output = baos.toByteArray();
+
+ // Convert byte array into String
+ byte[] base64 = Base64.encodeBase64(output);
+ String sComp = new String(base64, UTF8);
+
+ long diff = System.currentTimeMillis() - start;
+ System.out.println("Compressed text from " + input.length + " to "
+ + sComp.getBytes().length + " in " + diff + " ms");
+ System.out.println("Compressed text = '" + sComp + "'");
+
+ return sComp;
+ }
+
+ private String inflateString(String string) throws Exception
+ {
+ byte[] input = string.getBytes();
+
+ // First convert Base64 string back to binary array
+ byte[] bytes = Base64.decodeBase64(input);
+
+ // Set string as input data for decompressor
+ Inflater decompressor = new Inflater();
+ decompressor.setInput(bytes);
+
+ // Decompress the data
+ ByteArrayOutputStream bos = new ByteArrayOutputStream(input.length);
+ byte[] buf = new byte[1024];
+ while (!decompressor.finished())
+ {
+ int count = decompressor.inflate(buf);
+ bos.write(buf, 0, count);
+ }
+ bos.close();
+ byte[] output = bos.toByteArray();
+
+ // Get the decompressed data
+ return new String(output, UTF8);
+ }
+
+ /**
+ * @see javax.jms.ExceptionListener#onException(javax.jms.JMSException)
+ */
+ public void onException(JMSException e)
+ {
+ System.err.println(e.getMessage());
+ e.printStackTrace(System.err);
+ }
+
+
+}
diff --git a/Final/java/client/src/old_test/java/org/apache/qpid/pubsub1/TestPublisher.java b/Final/java/client/src/old_test/java/org/apache/qpid/pubsub1/TestPublisher.java
new file mode 100644
index 0000000000..33891142b5
--- /dev/null
+++ b/Final/java/client/src/old_test/java/org/apache/qpid/pubsub1/TestPublisher.java
@@ -0,0 +1,176 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.pubsub1;
+
+import org.apache.log4j.Logger;
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.AMQException;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.exchange.ExchangeDefaults;
+import org.apache.qpid.url.URLSyntaxException;
+import org.apache.qpid.client.AMQTopic;
+import org.apache.qpid.jms.MessageProducer;
+import org.apache.qpid.jms.Session;
+
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageListener;
+import javax.jms.TextMessage;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+/**
+ * A client that behaves as follows:
+ * <ul><li>Connects to a queue, whose name is specified as a cmd-line argument</li>
+ * <li>Creates a temporary queue</li>
+ * <li>Creates messages containing a property that is the name of the temporary queue</li>
+ * <li>Fires off a message on the original queue and waits for a response on the temporary queue</li>
+ * </ul>
+ *
+ */
+public class TestPublisher
+{
+ private static final Logger _log = Logger.getLogger(TestPublisher.class);
+
+ private AMQConnection _connection;
+
+ private Session _session;
+
+ private class CallbackHandler implements MessageListener
+ {
+ private int _expectedMessageCount;
+
+ private int _actualMessageCount;
+
+ private long _startTime;
+
+ public CallbackHandler(int expectedMessageCount, long startTime)
+ {
+ _expectedMessageCount = expectedMessageCount;
+ _startTime = startTime;
+ }
+
+ public void onMessage(Message m)
+ {
+ if (_log.isDebugEnabled())
+ {
+ _log.debug("Message received: " + m);
+ }
+ _actualMessageCount++;
+ if (_actualMessageCount%1000 == 0)
+ {
+ _log.info("Received message count: " + _actualMessageCount);
+ }
+ /*if (!"henson".equals(m.toString()))
+ {
+ _log.error("AbstractJMSMessage response not correct: expected 'henson' but got " + m.toString());
+ }
+ else
+ {
+ if (_log.isDebugEnabled())
+ {
+ _log.debug("AbstractJMSMessage " + m + " received");
+ }
+ else
+ {
+ _log.info("AbstractJMSMessage received");
+ }
+ } */
+
+ if (_actualMessageCount == _expectedMessageCount)
+ {
+ long timeTaken = System.currentTimeMillis() - _startTime;
+ System.out.println("Total time taken to receive " + _expectedMessageCount+ " messages was " +
+ timeTaken + "ms, equivalent to " +
+ (_expectedMessageCount/(timeTaken/1000.0)) + " messages per second");
+ }
+ }
+ }
+
+ public TestPublisher(String host, int port, String clientID, String commandQueueName,
+ final int messageCount) throws AMQException, URLSyntaxException
+ {
+ try
+ {
+ createConnection(host, port, clientID);
+
+ _session = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ AMQTopic destination = new AMQTopic(_session.getDefaultTopicExchangeName(), new AMQShortString(commandQueueName));
+ MessageProducer producer = (MessageProducer) _session.createProducer(destination);
+
+ _connection.start();
+ //TextMessage msg = _session.createTextMessage(tempDestination.getQueueName() + "/Presented to in conjunction with Mahnah Mahnah and the Snowths");
+ final long startTime = System.currentTimeMillis();
+
+ for (int i = 0; i < messageCount; i++)
+ {
+ TextMessage msg = _session.createTextMessage(destination.getTopicName() + "/Presented to in conjunction with Mahnah Mahnah and the Snowths: " + i);
+
+ //msg.setIntProperty("a",i % 2);
+ //msg.setIntProperty("b",i % 4);
+
+ producer.send(msg);
+ }
+ _log.info("Finished sending " + messageCount + " messages");
+ }
+ catch (JMSException e)
+ {
+ e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
+ }
+ }
+
+ private void createConnection(String host, int port, String clientID) throws AMQException, URLSyntaxException
+ {
+ _connection = new AMQConnection(host, port, "guest", "guest",
+ clientID, "/test");
+ }
+
+ /**
+ *
+ * @param args argument 1 if present specifies the name of the temporary queue to create. Leaving it blank
+ * means the server will allocate a name.
+ */
+ public static void main(String[] args) throws URLSyntaxException
+ {
+ if (args.length == 0)
+ {
+ System.err.println("Usage: TestPublisher <host> <port> <command queue name> <number of messages>");
+ }
+ try
+ {
+ int port = Integer.parseInt(args[1]);
+ InetAddress address = InetAddress.getLocalHost();
+ String clientID = address.getHostName() + System.currentTimeMillis();
+ TestPublisher client = new TestPublisher(args[0], port, clientID, args[2], Integer.parseInt(args[3]));
+ }
+ catch (UnknownHostException e)
+ {
+ e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
+ }
+ catch (AMQException e)
+ {
+ System.err.println("Error in client: " + e);
+ e.printStackTrace();
+ }
+
+ //System.exit(0);
+ }
+}
diff --git a/Final/java/client/src/old_test/java/org/apache/qpid/pubsub1/TestSubscriber.java b/Final/java/client/src/old_test/java/org/apache/qpid/pubsub1/TestSubscriber.java
new file mode 100644
index 0000000000..450d9b3914
--- /dev/null
+++ b/Final/java/client/src/old_test/java/org/apache/qpid/pubsub1/TestSubscriber.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.pubsub1;
+
+import org.apache.log4j.Logger;
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.client.AMQTopic;
+import org.apache.qpid.jms.Session;
+import org.apache.qpid.exchange.ExchangeDefaults;
+import org.apache.qpid.framing.AMQShortString;
+
+import javax.jms.MessageConsumer;
+import javax.jms.MessageListener;
+import javax.jms.Topic;
+import java.net.InetAddress;
+
+public class TestSubscriber
+{
+ private static final Logger _logger = Logger.getLogger(TestSubscriber.class);
+
+ private static class TestMessageListener implements MessageListener
+ {
+ private String _name;
+
+ private int _expectedMessageCount;
+
+ private int _messageCount;
+
+ private long _startTime = 0;
+
+ public TestMessageListener(String name, int expectedMessageCount)
+ {
+ _name = name;
+ _expectedMessageCount = expectedMessageCount;
+ }
+
+ public void onMessage(javax.jms.Message message)
+ {
+ if (_messageCount++ == 0)
+ {
+ _startTime = System.currentTimeMillis();
+ }
+ if (_logger.isInfoEnabled())
+ {
+ _logger.info(_name + " got message '" + message + "'");
+ }
+ if (_messageCount == _expectedMessageCount)
+ {
+ long totalTime = System.currentTimeMillis() - _startTime;
+ _logger.error(_name + ": Total time to receive " + _messageCount + " messages was " +
+ totalTime + "ms. Rate is " + (_messageCount/(totalTime/1000.0)));
+ }
+ if (_messageCount > _expectedMessageCount)
+ {
+ _logger.error("Oops! More messages received than expected (" + _messageCount + ")");
+ }
+ }
+ }
+
+ public static void main(String[] args)
+ {
+ _logger.info("Starting...");
+
+ if (args.length != 7)
+ {
+ System.out.println("Usage: host port username password virtual-path expectedMessageCount selector");
+ System.exit(1);
+ }
+ try
+ {
+ InetAddress address = InetAddress.getLocalHost();
+ AMQConnection con1 = new AMQConnection(args[0], Integer.parseInt(args[1]), args[2], args[3],
+ address.getHostName(), args[4]);
+ final Session session1 = con1.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ AMQConnection con2 = new AMQConnection(args[0], Integer.parseInt(args[1]), args[2], args[3],
+ address.getHostName(), args[4]);
+ final Session session2 = con2.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ String selector = args[6];
+
+ final int expectedMessageCount = Integer.parseInt(args[5]);
+ _logger.info("Message selector is <" + selector + ">...");
+
+ Topic t = new AMQTopic(session1.getDefaultTopicExchangeName(), new AMQShortString("cbr"));
+ MessageConsumer consumer1 = session1.createConsumer(t,
+ 100, false, false, selector);
+ MessageConsumer consumer2 = session2.createConsumer(t,
+ 100, false, false, selector);
+
+ consumer1.setMessageListener(new TestMessageListener("ML 1", expectedMessageCount));
+ consumer2.setMessageListener(new TestMessageListener("ML 2", expectedMessageCount));
+ con1.start();
+ con2.start();
+ }
+ catch (Throwable t)
+ {
+ System.err.println("Fatal error: " + t);
+ t.printStackTrace();
+ }
+
+ System.out.println("Waiting...");
+ }
+}
+
diff --git a/Final/java/client/src/old_test/java/org/apache/qpid/test/unit/client/connection/TestManyConnections.java b/Final/java/client/src/old_test/java/org/apache/qpid/test/unit/client/connection/TestManyConnections.java
new file mode 100644
index 0000000000..f59b36166a
--- /dev/null
+++ b/Final/java/client/src/old_test/java/org/apache/qpid/test/unit/client/connection/TestManyConnections.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.test.unit.client.connection;
+
+import org.apache.qpid.AMQException;
+import org.apache.qpid.url.URLSyntaxException;
+import org.apache.qpid.client.AMQConnection;
+import org.apache.log4j.Logger;
+
+import junit.framework.TestCase;
+
+public class TestManyConnections extends TestCase
+{
+ private static final Logger _log = Logger.getLogger(TestManyConnections.class);
+
+ private AMQConnection[] _connections;
+
+ private void createConnection(int index, String brokerHosts, String clientID, String username, String password,
+ String vpath) throws AMQException, URLSyntaxException
+ {
+ _connections[index] = new AMQConnection(brokerHosts, username, password,
+ clientID, vpath);
+ }
+
+ private void createConnections(int count) throws AMQException, URLSyntaxException
+ {
+ _connections = new AMQConnection[count];
+ long startTime = System.currentTimeMillis();
+ for (int i = 0; i < count; i++)
+ {
+ createConnection(i, "vm://:1", "myClient" + i, "guest", "guest", "test");
+ }
+ long endTime = System.currentTimeMillis();
+ _log.info("Time to create " + count + " connections: " + (endTime - startTime) +
+ "ms");
+ }
+
+ public void testCreate10Connections() throws AMQException, URLSyntaxException
+ {
+ createConnections(10);
+ }
+
+ public void testCreate50Connections() throws AMQException, URLSyntaxException
+ {
+ createConnections(50);
+ }
+
+ public void testCreate100Connections() throws AMQException, URLSyntaxException
+ {
+ createConnections(100);
+ }
+
+ public void testCreate250Connections() throws AMQException, URLSyntaxException
+ {
+ createConnections(250);
+ }
+
+ public void testCreate500Connections() throws AMQException, URLSyntaxException
+ {
+ createConnections(500);
+ }
+
+ public void testCreate1000Connections() throws AMQException, URLSyntaxException
+ {
+ createConnections(1000);
+ }
+
+ public void testCreate5000Connections() throws AMQException, URLSyntaxException
+ {
+ createConnections(5000);
+ }
+
+ public static junit.framework.Test suite()
+ {
+ return new junit.framework.TestSuite(TestManyConnections.class);
+ }
+}
diff --git a/Final/java/client/src/old_test/java/org/apache/qpid/test/unit/jndi/PropertiesFileInitialContextFactoryTest.java b/Final/java/client/src/old_test/java/org/apache/qpid/test/unit/jndi/PropertiesFileInitialContextFactoryTest.java
new file mode 100644
index 0000000000..5ab5722146
--- /dev/null
+++ b/Final/java/client/src/old_test/java/org/apache/qpid/test/unit/jndi/PropertiesFileInitialContextFactoryTest.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.test.unit.jndi;
+
+import org.apache.qpid.client.AMQConnectionFactory;
+import org.apache.qpid.client.AMQQueue;
+import org.apache.qpid.client.AMQTopic;
+
+import javax.naming.Context;
+import javax.naming.InitialContext;
+import javax.naming.NamingException;
+import javax.naming.spi.InitialContextFactory;
+import java.util.Properties;
+import java.io.InputStream;
+
+
+import junit.framework.TestCase;
+
+public class PropertiesFileInitialContextFactoryTest extends TestCase
+{
+ InitialContextFactory contextFactory;
+ Properties _properties;
+ Properties _fileProperties;
+
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+
+ //create simple set of hardcoded props
+ _properties = new Properties();
+ _properties.put("java.naming.factory.initial", "org.apache.qpid.jndi.PropertiesFileInitialContextFactory");
+ _properties.put("connectionfactory.local", "amqp://guest:guest@clientid/testpath?brokerlist='vm://:1'");
+ _properties.put("queue.MyQueue", "example.MyQueue");
+ _properties.put("topic.ibmStocks", "stocks.nyse.ibm");
+ _properties.put("destination.direct", "direct://amq.direct//directQueue");
+
+ //create properties from file as a more realistic test
+ _fileProperties = new Properties();
+ ClassLoader cl = this.getClass().getClassLoader();
+ InputStream is = cl.getResourceAsStream("org/apache/qpid/test/unit/jndi/example.properties");
+ _fileProperties.load(is);
+ }
+
+ /**
+ * Test using hardcoded properties
+ */
+ public void testWithoutFile()
+ {
+ Context ctx = null;
+
+ try
+ {
+ ctx = new InitialContext(_properties);
+ }
+ catch (NamingException ne)
+ {
+ fail("Error loading context:" + ne);
+ }
+
+ checkPropertiesMatch(ctx, "Using hardcoded properties: ");
+ }
+
+ /**
+ * Test using properties from example file
+ */
+ public void testWithFile()
+ {
+ Context ctx = null;
+
+ try
+ {
+ ctx = new InitialContext(_fileProperties);
+ }
+ catch (Exception e)
+ {
+ fail("Error loading context:" + e);
+ }
+
+ checkPropertiesMatch(ctx, "Using properties from file: ");
+ }
+
+ public void tearDown()
+ {
+ _properties = null;
+ _fileProperties = null;
+ }
+
+ public static junit.framework.Test suite()
+ {
+ return new junit.framework.TestSuite(PropertiesFileInitialContextFactoryTest.class);
+ }
+
+ private void checkPropertiesMatch(Context ctx, String errorInfo)
+ {
+ try
+ {
+ AMQConnectionFactory cf = (AMQConnectionFactory) ctx.lookup("local");
+ assertEquals("amqp://guest:guest@clientid/testpath?brokerlist='vm://:1'", cf.getConnectionURL().toString());
+ }
+ catch (NamingException ne)
+ {
+ fail(errorInfo + "Unable to create Connection Factory:" + ne);
+ }
+
+ try
+ {
+ AMQQueue queue = (AMQQueue) ctx.lookup("MyQueue");
+ assertEquals("example.MyQueue", queue.getRoutingKey().toString());
+ }
+ catch (NamingException ne)
+ {
+ fail(errorInfo + "Unable to create queue:" + ne);
+ }
+
+ try
+ {
+ AMQTopic topic = (AMQTopic) ctx.lookup("ibmStocks");
+ assertEquals("stocks.nyse.ibm", topic.getTopicName().toString());
+ }
+ catch (Exception ne)
+ {
+ fail(errorInfo + "Unable to create topic:" + ne);
+ }
+
+ try
+ {
+ AMQQueue direct = (AMQQueue) ctx.lookup("direct");
+ assertEquals("directQueue", direct.getRoutingKey().toString());
+ }
+ catch (NamingException ne)
+ {
+ fail(errorInfo + "Unable to create direct destination:" + ne);
+ }
+ }
+}
diff --git a/Final/java/client/src/old_test/java/org/apache/qpid/test/unit/jndi/example.properties b/Final/java/client/src/old_test/java/org/apache/qpid/test/unit/jndi/example.properties
new file mode 100644
index 0000000000..ea9dc5ae0e
--- /dev/null
+++ b/Final/java/client/src/old_test/java/org/apache/qpid/test/unit/jndi/example.properties
@@ -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.
+
+java.naming.factory.initial = org.apache.qpid.jndi.PropertiesFileInitialContextFactory
+
+# use the following property to configure the default connector
+#java.naming.provider.url - ignored.
+
+# register some connection factories
+# connectionfactory.[jndiname] = [ConnectionURL]
+connectionfactory.local = amqp://guest:guest@clientid/testpath?brokerlist='vm://:1'
+
+# register some queues in JNDI using the form
+# queue.[jndiName] = [physicalName]
+queue.MyQueue = example.MyQueue
+
+# register some topics in JNDI using the form
+# topic.[jndiName] = [physicalName]
+topic.ibmStocks = stocks.nyse.ibm
+
+# Register an AMQP destination in JNDI
+# NOTE: Qpid currently only supports direct,topics and headers
+# destination.[jniName] = [BindingURL]
+destination.direct = direct://amq.direct//directQueue
diff --git a/Final/java/client/src/old_test/java/org/apache/qpid/topic/Config.java b/Final/java/client/src/old_test/java/org/apache/qpid/topic/Config.java
new file mode 100644
index 0000000000..bb740f9094
--- /dev/null
+++ b/Final/java/client/src/old_test/java/org/apache/qpid/topic/Config.java
@@ -0,0 +1,243 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.topic;
+
+import org.apache.qpid.client.AMQSession;
+import org.apache.qpid.config.ConnectorConfig;
+import org.apache.qpid.config.ConnectionFactoryInitialiser;
+import org.apache.qpid.config.Connector;
+import org.apache.qpid.config.AbstractConfig;
+
+import javax.jms.Connection;
+import javax.jms.ConnectionFactory;
+
+class Config extends AbstractConfig implements ConnectorConfig
+{
+
+ private String host = "localhost";
+ private int port = 5672;
+ private String factory = null;
+
+ private int payload = 256;
+ private int messages = 1000;
+ private int clients = 1;
+ private int batch = 1;
+ private long delay = 1;
+ private int warmup;
+ private int ackMode= AMQSession.NO_ACKNOWLEDGE;
+ private String clientId;
+ private String subscriptionId;
+ private boolean persistent;
+
+ public Config()
+ {
+ }
+
+ int getAckMode()
+ {
+ return ackMode;
+ }
+
+ void setPayload(int payload)
+ {
+ this.payload = payload;
+ }
+
+ int getPayload()
+ {
+ return payload;
+ }
+
+ void setClients(int clients)
+ {
+ this.clients = clients;
+ }
+
+ int getClients()
+ {
+ return clients;
+ }
+
+ void setMessages(int messages)
+ {
+ this.messages = messages;
+ }
+
+ int getMessages()
+ {
+ return messages;
+ }
+
+ public String getHost()
+ {
+ return host;
+ }
+
+ public void setHost(String host)
+ {
+ this.host = host;
+ }
+
+ public int getPort()
+ {
+ return port;
+ }
+
+ public String getFactory()
+ {
+ return factory;
+ }
+
+ public void setPort(int port)
+ {
+ this.port = port;
+ }
+
+ int getBatch()
+ {
+ return batch;
+ }
+
+ void setBatch(int batch)
+ {
+ this.batch = batch;
+ }
+
+ int getWarmup()
+ {
+ return warmup;
+ }
+
+ void setWarmup(int warmup)
+ {
+ this.warmup = warmup;
+ }
+
+ public long getDelay()
+ {
+ return delay;
+ }
+
+ public void setDelay(long delay)
+ {
+ this.delay = delay;
+ }
+
+ String getClientId()
+ {
+ return clientId;
+ }
+
+ String getSubscriptionId()
+ {
+ return subscriptionId;
+ }
+
+ boolean usePersistentMessages()
+ {
+ return persistent;
+ }
+
+ public void setOption(String key, String value)
+ {
+ if("-host".equalsIgnoreCase(key))
+ {
+ setHost(value);
+ }
+ else if("-port".equalsIgnoreCase(key))
+ {
+ try
+ {
+ setPort(Integer.parseInt(value));
+ }
+ catch(NumberFormatException e)
+ {
+ throw new RuntimeException("Bad port number: " + value);
+ }
+ }
+ else if("-payload".equalsIgnoreCase(key))
+ {
+ setPayload(parseInt("Bad payload size", value));
+ }
+ else if("-messages".equalsIgnoreCase(key))
+ {
+ setMessages(parseInt("Bad message count", value));
+ }
+ else if("-clients".equalsIgnoreCase(key))
+ {
+ setClients(parseInt("Bad client count", value));
+ }
+ else if("-batch".equalsIgnoreCase(key))
+ {
+ setBatch(parseInt("Bad batch count", value));
+ }
+ else if("-delay".equalsIgnoreCase(key))
+ {
+ setDelay(parseLong("Bad batch delay", value));
+ }
+ else if("-warmup".equalsIgnoreCase(key))
+ {
+ setWarmup(parseInt("Bad warmup count", value));
+ }
+ else if("-ack".equalsIgnoreCase(key))
+ {
+ ackMode = parseInt("Bad ack mode", value);
+ }
+ else if("-factory".equalsIgnoreCase(key))
+ {
+ factory = value;
+ }
+ else if("-clientId".equalsIgnoreCase(key))
+ {
+ clientId = value;
+ }
+ else if("-subscriptionId".equalsIgnoreCase(key))
+ {
+ subscriptionId = value;
+ }
+ else if("-persistent".equalsIgnoreCase(key))
+ {
+ persistent = "true".equalsIgnoreCase(value);
+ }
+ else
+ {
+ System.out.println("Ignoring unrecognised option: " + key);
+ }
+ }
+
+ static String getAckModeDescription(int ackMode)
+ {
+ switch(ackMode)
+ {
+ case AMQSession.NO_ACKNOWLEDGE: return "NO_ACKNOWLEDGE";
+ case AMQSession.AUTO_ACKNOWLEDGE: return "AUTO_ACKNOWLEDGE";
+ case AMQSession.CLIENT_ACKNOWLEDGE: return "CLIENT_ACKNOWLEDGE";
+ case AMQSession.DUPS_OK_ACKNOWLEDGE: return "DUPS_OK_ACKNOWELDGE";
+ case AMQSession.PRE_ACKNOWLEDGE: return "PRE_ACKNOWLEDGE";
+ }
+ return "AckMode=" + ackMode;
+ }
+
+ public Connection createConnection() throws Exception
+ {
+ return new Connector().createConnection(this);
+ }
+}
diff --git a/Final/java/client/src/old_test/java/org/apache/qpid/topic/Listener.java b/Final/java/client/src/old_test/java/org/apache/qpid/topic/Listener.java
new file mode 100644
index 0000000000..47c608cfe4
--- /dev/null
+++ b/Final/java/client/src/old_test/java/org/apache/qpid/topic/Listener.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.topic;
+
+import javax.jms.Connection;
+import javax.jms.Message;
+import javax.jms.MessageListener;
+import javax.jms.MessageProducer;
+import javax.jms.Session;
+
+public class Listener implements MessageListener
+{
+ private final Connection _connection;
+ private final MessageProducer _controller;
+ private final javax.jms.Session _session;
+ private final MessageFactory _factory;
+ private boolean init;
+ private int count;
+ private long start;
+
+ Listener(Connection connection, int ackMode) throws Exception
+ {
+ this(connection, ackMode, null);
+ }
+
+ Listener(Connection connection, int ackMode, String name) throws Exception
+ {
+ _connection = connection;
+ _session = connection.createSession(false, ackMode);
+ _factory = new MessageFactory(_session);
+
+ //register for events
+ if(name == null)
+ {
+ _factory.createTopicConsumer().setMessageListener(this);
+ }
+ else
+ {
+ _factory.createDurableTopicConsumer(name).setMessageListener(this);
+ }
+
+ _connection.start();
+
+ _controller = _factory.createControlPublisher();
+ System.out.println("Waiting for messages " +
+ Config.getAckModeDescription(ackMode)
+ + (name == null ? "" : " (subscribed with name " + name + " and client id " + connection.getClientID() + ")")
+ + "...");
+
+ }
+
+ private void shutdown()
+ {
+ try
+ {
+ _session.close();
+ _connection.stop();
+ _connection.close();
+ }
+ catch(Exception e)
+ {
+ e.printStackTrace(System.out);
+ }
+ }
+
+ private void report()
+ {
+ try
+ {
+ String msg = getReport();
+ _controller.send(_factory.createReportResponseMessage(msg));
+ System.out.println("Sent report: " + msg);
+ }
+ catch(Exception e)
+ {
+ e.printStackTrace(System.out);
+ }
+ }
+
+ private String getReport()
+ {
+ long time = (System.currentTimeMillis() - start);
+ return "Received " + count + " in " + time + "ms";
+ }
+
+ public void onMessage(Message message)
+ {
+ if(!init)
+ {
+ start = System.currentTimeMillis();
+ count = 0;
+ init = true;
+ }
+
+ if(_factory.isShutdown(message))
+ {
+ shutdown();
+ }
+ else if(_factory.isReport(message))
+ {
+ //send a report:
+ report();
+ init = false;
+ }
+ else if (++count % 100 == 0)
+ {
+ System.out.println("Received " + count + " messages.");
+ }
+ }
+
+ public static void main(String[] argv) throws Exception
+ {
+ Config config = new Config();
+ config.setOptions(argv);
+
+ Connection con = config.createConnection();
+ if(config.getClientId() != null)
+ {
+ con.setClientID(config.getClientId());
+ }
+ new Listener(con, config.getAckMode(), config.getSubscriptionId());
+ }
+}
diff --git a/Final/java/client/src/old_test/java/org/apache/qpid/topic/MessageFactory.java b/Final/java/client/src/old_test/java/org/apache/qpid/topic/MessageFactory.java
new file mode 100644
index 0000000000..39d64069d1
--- /dev/null
+++ b/Final/java/client/src/old_test/java/org/apache/qpid/topic/MessageFactory.java
@@ -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.
+ *
+ */
+package org.apache.qpid.topic;
+
+import org.apache.qpid.client.AMQSession;
+import org.apache.qpid.client.AMQTopic;
+import org.apache.qpid.exchange.ExchangeDefaults;
+import org.apache.qpid.framing.AMQShortString;
+
+import javax.jms.*;
+
+/**
+ */
+class MessageFactory
+{
+ private static final char[] DATA = "abcdefghijklmnopqrstuvwxyz".toCharArray();
+
+ private final Session _session;
+ private final Topic _topic;
+ private final Topic _control;
+ private final byte[] _payload;
+
+
+ MessageFactory(Session session) throws JMSException
+ {
+ this(session, 256);
+ }
+
+ MessageFactory(Session session, int size) throws JMSException
+ {
+ _session = session;
+ if(session instanceof AMQSession)
+ {
+ _topic = new AMQTopic(((AMQSession)session).getDefaultTopicExchangeName(),new AMQShortString("topictest.messages"));
+ _control = new AMQTopic(((AMQSession)session).getDefaultTopicExchangeName(),new AMQShortString("topictest.control"));
+ }
+ else
+ {
+ _topic = session.createTopic("topictest.messages");
+ _control = session.createTopic("topictest.control");
+ }
+ _payload = new byte[size];
+
+ for(int i = 0; i < size; i++)
+ {
+ _payload[i] = (byte) DATA[i % DATA.length];
+ }
+ }
+
+ Topic getTopic()
+ {
+ return _topic;
+ }
+
+ Message createEventMessage() throws JMSException
+ {
+ BytesMessage msg = _session.createBytesMessage();
+ msg.writeBytes(_payload);
+ return msg;
+ }
+
+ Message createShutdownMessage() throws JMSException
+ {
+ return _session.createTextMessage("SHUTDOWN");
+ }
+
+ Message createReportRequestMessage() throws JMSException
+ {
+ return _session.createTextMessage("REPORT");
+ }
+
+ Message createReportResponseMessage(String msg) throws JMSException
+ {
+ return _session.createTextMessage(msg);
+ }
+
+ boolean isShutdown(Message m)
+ {
+ return checkText(m, "SHUTDOWN");
+ }
+
+ boolean isReport(Message m)
+ {
+ return checkText(m, "REPORT");
+ }
+
+ Object getReport(Message m)
+ {
+ try
+ {
+ return ((TextMessage) m).getText();
+ }
+ catch (JMSException e)
+ {
+ e.printStackTrace(System.out);
+ return e.toString();
+ }
+ }
+
+ MessageConsumer createTopicConsumer() throws Exception
+ {
+ return _session.createConsumer(_topic);
+ }
+
+ MessageConsumer createDurableTopicConsumer(String name) throws Exception
+ {
+ return _session.createDurableSubscriber(_topic, name);
+ }
+
+ MessageConsumer createControlConsumer() throws Exception
+ {
+ return _session.createConsumer(_control);
+ }
+
+ MessageProducer createTopicPublisher() throws Exception
+ {
+ return _session.createProducer(_topic);
+ }
+
+ MessageProducer createControlPublisher() throws Exception
+ {
+ return _session.createProducer(_control);
+ }
+
+ private static boolean checkText(Message m, String s)
+ {
+ try
+ {
+ return m instanceof TextMessage && ((TextMessage) m).getText().equals(s);
+ }
+ catch (JMSException e)
+ {
+ e.printStackTrace(System.out);
+ return false;
+ }
+ }
+}
diff --git a/Final/java/client/src/old_test/java/org/apache/qpid/topic/Publisher.java b/Final/java/client/src/old_test/java/org/apache/qpid/topic/Publisher.java
new file mode 100644
index 0000000000..d788029ee9
--- /dev/null
+++ b/Final/java/client/src/old_test/java/org/apache/qpid/topic/Publisher.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.topic;
+
+import javax.jms.*;
+
+public class Publisher implements MessageListener
+{
+ private final Object _lock = new Object();
+ private final Connection _connection;
+ private final Session _session;
+ private final MessageFactory _factory;
+ private final MessageProducer _publisher;
+ private int _count;
+
+ Publisher(Connection connection, int size, int ackMode, boolean persistent) throws Exception
+ {
+ _connection = connection;
+ _session = _connection.createSession(false, ackMode);
+ _factory = new MessageFactory(_session, size);
+ _publisher = _factory.createTopicPublisher();
+ _publisher.setDeliveryMode(persistent ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT);
+ System.out.println("Publishing " + (persistent ? "persistent" : "non-persistent") + " messages of " + size + " bytes, " + Config.getAckModeDescription(ackMode) + ".");
+ }
+
+ private void test(Config config) throws Exception
+ {
+ test(config.getBatch(), config.getDelay(), config.getMessages(), config.getClients(), config.getWarmup());
+ }
+
+ private void test(int batches, long delay, int msgCount, int consumerCount, int warmup) throws Exception
+ {
+ _factory.createControlConsumer().setMessageListener(this);
+ _connection.start();
+
+ if(warmup > 0)
+ {
+ System.out.println("Runing warmup (" + warmup + " msgs)");
+ long time = batch(warmup, consumerCount);
+ System.out.println("Warmup completed in " + time + "ms");
+ }
+
+ long[] times = new long[batches];
+ for(int i = 0; i < batches; i++)
+ {
+ if(i > 0) Thread.sleep(delay*1000);
+ times[i] = batch(msgCount, consumerCount);
+ System.out.println("Batch " + (i+1) + " of " + batches + " completed in " + times[i] + " ms.");
+ }
+
+ long min = min(times);
+ long max = max(times);
+ System.out.println("min: " + min + ", max: " + max + " avg: " + avg(times, min, max));
+
+ //request shutdown
+ _publisher.send(_factory.createShutdownMessage());
+
+ _connection.stop();
+ _connection.close();
+ }
+
+ private long batch(int msgCount, int consumerCount) throws Exception
+ {
+ _count = consumerCount;
+ long start = System.currentTimeMillis();
+ publish(msgCount);
+ waitForCompletion(consumerCount);
+ return System.currentTimeMillis() - start;
+ }
+
+ private void publish(int count) throws Exception
+ {
+
+ //send events
+ for (int i = 0; i < count; i++)
+ {
+ _publisher.send(_factory.createEventMessage());
+ if ((i + 1) % 100 == 0)
+ {
+ System.out.println("Sent " + (i + 1) + " messages");
+ }
+ }
+
+ //request report
+ _publisher.send(_factory.createReportRequestMessage());
+ }
+
+ private void waitForCompletion(int consumers) throws Exception
+ {
+ System.out.println("Waiting for completion...");
+ synchronized (_lock)
+ {
+ while (_count > 0)
+ {
+ _lock.wait();
+ }
+ }
+ }
+
+
+ public void onMessage(Message message)
+ {
+ System.out.println("Received report " + _factory.getReport(message) + " " + --_count + " remaining");
+ if (_count == 0)
+ {
+ synchronized (_lock)
+ {
+ _lock.notify();
+ }
+ }
+ }
+
+ static long min(long[] times)
+ {
+ long min = times.length > 0 ? times[0] : 0;
+ for(int i = 0; i < times.length; i++)
+ {
+ min = Math.min(min, times[i]);
+ }
+ return min;
+ }
+
+ static long max(long[] times)
+ {
+ long max = times.length > 0 ? times[0] : 0;
+ for(int i = 0; i < times.length; i++)
+ {
+ max = Math.max(max, times[i]);
+ }
+ return max;
+ }
+
+ static long avg(long[] times, long min, long max)
+ {
+ long sum = 0;
+ for(int i = 0; i < times.length; i++)
+ {
+ sum += times[i];
+ }
+ sum -= min;
+ sum -= max;
+
+ return (sum / (times.length - 2));
+ }
+
+ public static void main(String[] argv) throws Exception
+ {
+ Config config = new Config();
+ config.setOptions(argv);
+
+ Connection con = config.createConnection();
+ int size = config.getPayload();
+ int ackMode = config.getAckMode();
+ boolean persistent = config.usePersistentMessages();
+ new Publisher(con, size, ackMode, persistent).test(config);
+ }
+}
diff --git a/Final/java/client/src/old_test/java/org/apache/qpid/transacted/Config.java b/Final/java/client/src/old_test/java/org/apache/qpid/transacted/Config.java
new file mode 100644
index 0000000000..bd104e5407
--- /dev/null
+++ b/Final/java/client/src/old_test/java/org/apache/qpid/transacted/Config.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.transacted;
+
+import org.apache.qpid.config.ConnectorConfig;
+import org.apache.qpid.config.AbstractConfig;
+import org.apache.qpid.config.Connector;
+
+import javax.jms.Connection;
+
+class Config extends AbstractConfig implements ConnectorConfig
+{
+ private String host = "localhost";
+ private int port = 5672;
+ private String factory;
+ private boolean echo;
+ private int batch = 100;
+ private boolean persistent = true;
+
+ Config(String[] argv)
+ {
+ setOptions(argv);
+ }
+
+ Connection createConnection() throws Exception
+ {
+ return new Connector().createConnection(this);
+ }
+
+ public boolean isEchoOn()
+ {
+ return echo;
+ }
+
+ public boolean usePersistentMessages()
+ {
+ return persistent;
+ }
+
+ public int getBatchSize()
+ {
+ return batch;
+ }
+
+ public String getHost()
+ {
+ return host;
+ }
+
+ public int getPort()
+ {
+ return port;
+ }
+
+ public String getFactory()
+ {
+ return factory;
+ }
+
+ public void setOption(String key, String value)
+ {
+ if("-host".equalsIgnoreCase(key))
+ {
+ host = value;
+ }
+ else if("-port".equalsIgnoreCase(key))
+ {
+ port = parseInt("Bad port number", value);
+ }
+ else if("-factory".equalsIgnoreCase(key))
+ {
+ factory = value;
+ }
+ else if("-echo".equalsIgnoreCase(key))
+ {
+ echo = "true".equalsIgnoreCase(value);
+ }
+ else if("-persistent".equalsIgnoreCase(key))
+ {
+ persistent = "true".equalsIgnoreCase(value);
+ }
+ else if("-batch".equalsIgnoreCase(key))
+ {
+ batch = parseInt("Bad batch size", value);
+ }
+ else
+ {
+ System.out.println("Ignoring nrecognised option " + key);
+ }
+ }
+
+}
diff --git a/Final/java/client/src/old_test/java/org/apache/qpid/transacted/Ping.java b/Final/java/client/src/old_test/java/org/apache/qpid/transacted/Ping.java
new file mode 100644
index 0000000000..8f15bf089e
--- /dev/null
+++ b/Final/java/client/src/old_test/java/org/apache/qpid/transacted/Ping.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.transacted;
+
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.AMQException;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.exchange.ExchangeDefaults;
+import org.apache.qpid.client.AMQQueue;
+
+import javax.jms.Connection;
+import javax.jms.JMSException;
+import java.util.Arrays;
+
+public class Ping
+{
+ public static void main(String[] argv) throws Exception
+ {
+ Config config = new Config(argv);
+ Connection con = config.createConnection();
+ con.setClientID("ping");
+ new Relay(new AMQQueue(ExchangeDefaults.DIRECT_EXCHANGE_NAME, new AMQShortString("ping")), new AMQQueue(ExchangeDefaults.DIRECT_EXCHANGE_NAME, new AMQShortString("pong")), con,
+ config.isEchoOn(),
+ config.getBatchSize(),
+ config.usePersistentMessages()).start();
+ }
+}
diff --git a/Final/java/client/src/old_test/java/org/apache/qpid/transacted/Pong.java b/Final/java/client/src/old_test/java/org/apache/qpid/transacted/Pong.java
new file mode 100644
index 0000000000..f4f4b20d7c
--- /dev/null
+++ b/Final/java/client/src/old_test/java/org/apache/qpid/transacted/Pong.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.transacted;
+
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.AMQException;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.exchange.ExchangeDefaults;
+import org.apache.qpid.client.AMQQueue;
+
+import javax.jms.Connection;
+import javax.jms.JMSException;
+
+public class Pong
+{
+ public static void main(String[] argv) throws Exception
+ {
+ Config config = new Config(argv);
+ Connection con = config.createConnection();
+ con.setClientID("pong");
+ new Relay(new AMQQueue(ExchangeDefaults.DIRECT_EXCHANGE_NAME, new AMQShortString("pong")), new AMQQueue(ExchangeDefaults.DIRECT_EXCHANGE_NAME, new AMQShortString("ping")), con,
+ config.isEchoOn(),
+ config.getBatchSize(),
+ config.usePersistentMessages()).start();
+
+ }
+}
diff --git a/Final/java/client/src/old_test/java/org/apache/qpid/transacted/Relay.java b/Final/java/client/src/old_test/java/org/apache/qpid/transacted/Relay.java
new file mode 100644
index 0000000000..cede95e5f0
--- /dev/null
+++ b/Final/java/client/src/old_test/java/org/apache/qpid/transacted/Relay.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.transacted;
+
+import org.apache.qpid.client.AMQSession;
+
+import javax.jms.MessageProducer;
+import javax.jms.MessageConsumer;
+import javax.jms.Session;
+import javax.jms.Destination;
+import javax.jms.Connection;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.TextMessage;
+import javax.jms.DeliveryMode;
+
+class Relay implements Runnable
+{
+ private final Connection _con;
+ private final Session _session;
+ private final MessageConsumer _src;
+ private final MessageProducer _dest;
+ private final int _batch;
+ private final boolean _echo;
+ private int _counter;
+ private long start;
+ private boolean _running;
+
+ Relay(Destination src, Destination dest, Connection con) throws JMSException
+ {
+ this(src, dest, con, false, 100, true);
+ }
+
+ Relay(Destination src, Destination dest, Connection con, boolean echo, int batch, boolean persistent) throws JMSException
+ {
+ _echo = echo;
+ _batch = batch;
+ _con = con;
+ _session = con.createSession(true, AMQSession.NO_ACKNOWLEDGE);
+ _src = _session.createConsumer(src);
+ _dest = _session.createProducer(dest);
+ _dest.setDeliveryMode(persistent ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT);
+
+ }
+
+ public void run()
+ {
+ start = System.currentTimeMillis();
+ try{
+ while(true) relay();
+ }
+ catch(JMSException e)
+ {
+ e.printStackTrace();
+ }
+ try
+ {
+ _session.close();
+ }
+ catch (JMSException e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ void relay() throws JMSException
+ {
+ _dest.send(relay(_src.receive()));
+ _session.commit();
+ }
+
+ Message relay(Message in) throws JMSException
+ {
+ if(!_running)
+ {
+ System.out.println(_con.getClientID() + " started.");
+ _running = true;
+ }
+ if(++_counter % _batch == 0)
+ {
+ long time = System.currentTimeMillis() - start;
+ System.out.println(_batch + " iterations performed in " + time + " ms");
+ try
+ {
+ Thread.sleep(100);
+ }
+ catch (InterruptedException e)
+ {
+ e.printStackTrace();
+ }
+ start = System.currentTimeMillis();
+ }
+ if(_echo)
+ {
+ System.out.println("Received: " + ((TextMessage) in).getText());
+ }
+ return _session.createTextMessage(_con.getClientID() + _counter);
+ }
+
+ void start() throws InterruptedException, JMSException
+ {
+ Thread runner = new Thread(this);
+ runner.start();
+ _con.start();
+ System.out.println(_con.getClientID() + " waiting...");
+ runner.join();
+ _con.close();
+ }
+}
diff --git a/Final/java/client/src/old_test/java/org/apache/qpid/transacted/Start.java b/Final/java/client/src/old_test/java/org/apache/qpid/transacted/Start.java
new file mode 100644
index 0000000000..de718d828a
--- /dev/null
+++ b/Final/java/client/src/old_test/java/org/apache/qpid/transacted/Start.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.transacted;
+
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.AMQException;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.exchange.ExchangeDefaults;
+import org.apache.qpid.client.AMQQueue;
+
+import javax.jms.Connection;
+import javax.jms.JMSException;
+import javax.jms.Session;
+
+public class Start
+{
+ public static void main(String[] argv) throws Exception
+ {
+ Connection con = new Config(argv).createConnection();
+ AMQQueue ping = new AMQQueue(ExchangeDefaults.DIRECT_EXCHANGE_NAME, new AMQShortString("ping"));
+ Session session = con.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ session.createProducer(ping).send(session.createTextMessage("start"));
+ session.close();
+ con.close();
+ }
+}
diff --git a/Final/java/client/src/old_test/java/org/apache/qpid/weblogic/ServiceProvider.java b/Final/java/client/src/old_test/java/org/apache/qpid/weblogic/ServiceProvider.java
new file mode 100644
index 0000000000..71d806b338
--- /dev/null
+++ b/Final/java/client/src/old_test/java/org/apache/qpid/weblogic/ServiceProvider.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.weblogic;
+
+import org.apache.log4j.Logger;
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.client.AMQDestination;
+
+import javax.jms.*;
+import javax.naming.InitialContext;
+import javax.naming.NamingException;
+import javax.naming.Context;
+import java.net.InetAddress;
+import java.util.Hashtable;
+
+public class ServiceProvider
+{
+ private static final String JNDI_FACTORY = "weblogic.jndi.WLInitialContextFactory";
+ private static final String JMS_FACTORY = "transientJMSConnectionFactory";
+
+ private static final Logger _logger = Logger.getLogger(ServiceProvider.class);
+
+ private static MessageProducer _destinationProducer;
+
+ private static Queue _destinationQ;
+
+ public static void main(String[] args)
+ {
+ _logger.info("Starting...");
+
+ if (args.length != 2)
+ {
+ System.out.println("Usage: <WLS URI> <service queue>");
+ System.exit(1);
+ }
+ try
+ {
+ String url = args[0];
+ String receiveQueue = args[1];
+
+ final InitialContext ctx = getInitialContext(url);
+
+ QueueConnectionFactory qconFactory = (QueueConnectionFactory) ctx.lookup(JMS_FACTORY);
+ QueueConnection qcon = qconFactory.createQueueConnection();
+ final QueueSession qsession = qcon.createQueueSession(false, Session.CLIENT_ACKNOWLEDGE);
+ Queue receiveQ = (Queue) ctx.lookup(receiveQueue);
+
+ _logger.info("Service (queue) name is '" + receiveQ + "'...");
+
+ String selector = (args.length > 2 && args[2] != null && args[2].length() > 1) ? args[2] : null;
+
+ _logger.info("Message selector is <" + selector + ">...");
+
+ MessageConsumer consumer = qsession.createConsumer(receiveQ, selector);
+
+ consumer.setMessageListener(new MessageListener()
+ {
+ private int _messageCount;
+
+ public void onMessage(javax.jms.Message message)
+ {
+ //_logger.info("Got message '" + message + "'");
+
+ TextMessage tm = (TextMessage) message;
+
+ try
+ {
+ Queue responseQueue = (Queue)tm.getJMSReplyTo();
+ if (!responseQueue.equals(_destinationQ))
+ {
+ _destinationQ = responseQueue;
+ _logger.info("Creating destination for " + responseQueue);
+
+ try
+ {
+ _destinationProducer = qsession.createProducer(_destinationQ);
+ _destinationProducer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
+ }
+ catch (JMSException e)
+ {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+ _messageCount++;
+ if (_messageCount % 1000 == 0)
+ {
+ _logger.info("Received message total: " + _messageCount);
+ _logger.info("Sending response to '" + responseQueue + "'");
+ }
+
+ String payload = "This is a response: sing together: 'Mahnah mahnah...'" + tm.getText();
+ TextMessage msg = qsession.createTextMessage(payload);
+ if (tm.propertyExists("timeSent"))
+ {
+ _logger.info("timeSent property set on message");
+ final long timeSent = tm.getLongProperty("timeSent");
+ msg.setLongProperty("timeSent", timeSent);
+ _logger.info("time taken to go from service request to provider is: " + (System.currentTimeMillis() - timeSent));
+ }
+ _destinationProducer.send(msg);
+ if (_messageCount % 1000 == 0)
+ {
+ tm.acknowledge();
+ _logger.info("Sent response to '" + responseQueue + "'");
+ }
+ }
+ catch (JMSException e)
+ {
+ _logger.error("Error sending message: " + e, e);
+ }
+ }
+ });
+ qcon.start();
+ }
+ catch (Throwable t)
+ {
+ System.err.println("Fatal error: " + t);
+ t.printStackTrace();
+ }
+
+
+ System.out.println("Waiting...");
+ }
+
+ private static InitialContext getInitialContext(String url) throws NamingException
+ {
+ Hashtable env = new Hashtable();
+ env.put(Context.INITIAL_CONTEXT_FACTORY, JNDI_FACTORY);
+ env.put(Context.PROVIDER_URL, url);
+ return new InitialContext(env);
+ }
+}
diff --git a/Final/java/client/src/old_test/java/org/apache/qpid/weblogic/ServiceRequestingClient.java b/Final/java/client/src/old_test/java/org/apache/qpid/weblogic/ServiceRequestingClient.java
new file mode 100644
index 0000000000..2f64a1dde5
--- /dev/null
+++ b/Final/java/client/src/old_test/java/org/apache/qpid/weblogic/ServiceRequestingClient.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.weblogic;
+
+import org.apache.log4j.Logger;
+
+import javax.jms.*;
+import javax.naming.Context;
+import javax.naming.InitialContext;
+import javax.naming.NamingException;
+import java.util.Hashtable;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: U806869
+ * Date: 28-May-2005
+ * Time: 21:54:51
+ * To change this template use File | Settings | File Templates.
+ */
+public class ServiceRequestingClient
+{
+ private static final Logger _log = Logger.getLogger(ServiceRequestingClient.class);
+ private static final String JNDI_FACTORY = "weblogic.jndi.WLInitialContextFactory";
+ private static final String JMS_FACTORY = "transientJMSConnectionFactory";
+
+ private static class CallbackHandler implements MessageListener
+ {
+ private int _expectedMessageCount;
+
+ private int _actualMessageCount;
+
+ private long _startTime;
+
+ private long _averageLatency;
+
+ public CallbackHandler(int expectedMessageCount, long startTime)
+ {
+ _expectedMessageCount = expectedMessageCount;
+ _startTime = startTime;
+ }
+
+ public void onMessage(Message m)
+ {
+ if (_log.isDebugEnabled())
+ {
+ _log.debug("Message received: " + m);
+ }
+ try
+ {
+ if (m.propertyExists("timeSent"))
+ {
+ long timeSent = m.getLongProperty("timeSent");
+ long now = System.currentTimeMillis();
+ if (_averageLatency == 0)
+ {
+ _averageLatency = now - timeSent;
+ _log.info("Latency " + _averageLatency);
+ }
+ else
+ {
+ _log.info("Individual latency: " + (now-timeSent));
+ _averageLatency = (_averageLatency + (now - timeSent))/2;
+ _log.info("Average latency now: " + _averageLatency);
+ }
+ }
+ }
+ catch (JMSException e)
+ {
+ _log.error("Could not calculate latency");
+ }
+
+ _actualMessageCount++;
+ if (_actualMessageCount%1000 == 0)
+ {
+ try
+ {
+ m.acknowledge();
+ }
+ catch (JMSException e)
+ {
+ _log.error("Error acknowledging message");
+ }
+ _log.info("Received message count: " + _actualMessageCount);
+ }
+ /*if (!"henson".equals(m.toString()))
+ {
+ _log.error("Message response not correct: expected 'henson' but got " + m.toString());
+ }
+ else
+ {
+ if (_log.isDebugEnabled())
+ {
+ _log.debug("Message " + m + " received");
+ }
+ else
+ {
+ _log.info("Message received");
+ }
+ } */
+
+ if (_actualMessageCount == _expectedMessageCount)
+ {
+ long timeTaken = System.currentTimeMillis() - _startTime;
+ System.out.println("Total time taken to receive " + _expectedMessageCount+ " messages was " +
+ timeTaken + "ms, equivalent to " +
+ (_expectedMessageCount/(timeTaken/1000.0)) + " messages per second");
+ System.out.println("Average latency is: " + _averageLatency);
+ }
+ }
+ }
+
+ public static void main(String[] args) throws Exception
+ {
+ if (args.length != 3)
+ {
+ System.out.println("Usage: IXPublisher <WLS URL> <sendQueue> <count> will publish count messages to ");
+ System.out.println("queue sendQueue and waits for a response on a temp queue");
+ System.exit(1);
+ }
+
+ String url = args[0];
+ String sendQueue = args[1];
+ int messageCount = Integer.parseInt(args[2]);
+
+ InitialContext ctx = getInitialContext(url);
+
+ QueueConnectionFactory qconFactory = (QueueConnectionFactory) ctx.lookup(JMS_FACTORY);
+ QueueConnection qcon = qconFactory.createQueueConnection();
+ QueueSession qsession = qcon.createQueueSession(false, Session.CLIENT_ACKNOWLEDGE);
+ Queue sendQ = (Queue) ctx.lookup(sendQueue);
+ Queue receiveQ = qsession.createTemporaryQueue();
+ QueueSender qsender = qsession.createSender(sendQ);
+ qsender.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
+ _log.debug("Queue sender created for service queue " + sendQ);
+
+ javax.jms.MessageConsumer messageConsumer = (javax.jms.MessageConsumer) qsession.createConsumer(receiveQ);
+
+ //TextMessage msg = _session.createTextMessage(tempDestination.getQueueName() + "/Presented to in conjunction with Mahnah Mahnah and the Snowths");
+ final long startTime = System.currentTimeMillis();
+
+ messageConsumer.setMessageListener(new CallbackHandler(messageCount, startTime));
+ qcon.start();
+ for (int i = 0; i < messageCount; i++)
+ {
+ TextMessage msg = qsession.createTextMessage("/Presented to in conjunction with Mahnah Mahnah and the Snowths:" + i);
+ msg.setJMSReplyTo(receiveQ);
+ if (i%1000 == 0)
+ {
+ long timeNow = System.currentTimeMillis();
+ msg.setLongProperty("timeSent", timeNow);
+ }
+ qsender.send(msg);
+ }
+
+ new Thread("foo").start();
+ //qsession.close();
+ //qcon.close();
+ }
+
+ private static InitialContext getInitialContext(String url) throws NamingException
+ {
+ Hashtable env = new Hashtable();
+ env.put(Context.INITIAL_CONTEXT_FACTORY, JNDI_FACTORY);
+ env.put(Context.PROVIDER_URL, url);
+ return new InitialContext(env);
+ }
+}
diff --git a/Final/java/client/src/test/java/org/apache/mina/transport/vmpipe/support/VmPipeIdleStatusChecker.java b/Final/java/client/src/test/java/org/apache/mina/transport/vmpipe/support/VmPipeIdleStatusChecker.java
new file mode 100644
index 0000000000..5323ad28bf
--- /dev/null
+++ b/Final/java/client/src/test/java/org/apache/mina/transport/vmpipe/support/VmPipeIdleStatusChecker.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.mina.transport.vmpipe.support;
+
+import org.apache.mina.common.IdleStatus;
+
+import java.util.HashMap;
+import java.util.IdentityHashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+/**
+ * This file is a patch to override MINA, because of the IdentityHashMap bug. Workaround to be supplied in MINA 1.0.7.
+ * This patched file will be removed once upgraded onto a newer MINA.
+ *
+ * Dectects idle sessions and fires <tt>sessionIdle</tt> events to them.
+ *
+ * @author The Apache Directory Project (mina-dev@directory.apache.org)
+ */
+public class VmPipeIdleStatusChecker
+{
+ private static final VmPipeIdleStatusChecker INSTANCE = new VmPipeIdleStatusChecker();
+
+ public static VmPipeIdleStatusChecker getInstance()
+ {
+ return INSTANCE;
+ }
+
+ private final Map sessions = new HashMap(); // will use as a set
+
+ private final Worker worker = new Worker();
+
+ private VmPipeIdleStatusChecker()
+ {
+ worker.start();
+ }
+
+ public void addSession(VmPipeSessionImpl session)
+ {
+ synchronized (sessions)
+ {
+ sessions.put(session, session);
+ }
+ }
+
+ private class Worker extends Thread
+ {
+ private Worker()
+ {
+ super("VmPipeIdleStatusChecker");
+ setDaemon(true);
+ }
+
+ public void run()
+ {
+ for (;;)
+ {
+ try
+ {
+ Thread.sleep(1000);
+ }
+ catch (InterruptedException e)
+ { }
+
+ long currentTime = System.currentTimeMillis();
+
+ synchronized (sessions)
+ {
+ Iterator it = sessions.keySet().iterator();
+ while (it.hasNext())
+ {
+ VmPipeSessionImpl session = (VmPipeSessionImpl) it.next();
+ if (!session.isConnected())
+ {
+ it.remove();
+ }
+ else
+ {
+ notifyIdleSession(session, currentTime);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ private void notifyIdleSession(VmPipeSessionImpl session, long currentTime)
+ {
+ notifyIdleSession0(session, currentTime, session.getIdleTimeInMillis(IdleStatus.BOTH_IDLE), IdleStatus.BOTH_IDLE,
+ Math.max(session.getLastIoTime(), session.getLastIdleTime(IdleStatus.BOTH_IDLE)));
+ notifyIdleSession0(session, currentTime, session.getIdleTimeInMillis(IdleStatus.READER_IDLE), IdleStatus.READER_IDLE,
+ Math.max(session.getLastReadTime(), session.getLastIdleTime(IdleStatus.READER_IDLE)));
+ notifyIdleSession0(session, currentTime, session.getIdleTimeInMillis(IdleStatus.WRITER_IDLE), IdleStatus.WRITER_IDLE,
+ Math.max(session.getLastWriteTime(), session.getLastIdleTime(IdleStatus.WRITER_IDLE)));
+ }
+
+ private void notifyIdleSession0(VmPipeSessionImpl session, long currentTime, long idleTime, IdleStatus status,
+ long lastIoTime)
+ {
+ if ((idleTime > 0) && (lastIoTime != 0) && ((currentTime - lastIoTime) >= idleTime))
+ {
+ session.increaseIdleCount(status);
+ session.getFilterChain().fireSessionIdle(session, status);
+ }
+ }
+
+}
diff --git a/Final/java/client/src/test/java/org/apache/qpid/client/AMQQueueDeferredOrderingTest.java b/Final/java/client/src/test/java/org/apache/qpid/client/AMQQueueDeferredOrderingTest.java
new file mode 100644
index 0000000000..fe418535d6
--- /dev/null
+++ b/Final/java/client/src/test/java/org/apache/qpid/client/AMQQueueDeferredOrderingTest.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.client;
+
+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.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
+{
+
+ private static final int NUM_MESSAGES = 1000;
+
+ private AMQConnection con;
+ private Session session;
+ private AMQQueue queue;
+ private MessageConsumer consumer;
+
+ private static final Logger _logger = LoggerFactory.getLogger(AMQQueueDeferredOrderingTest.class);
+
+ private ASyncProducer producerThread;
+ private static final String BROKER = "vm://:1";
+
+ private class ASyncProducer extends Thread
+ {
+
+ private MessageProducer producer;
+ private final Logger _logger = LoggerFactory.getLogger(ASyncProducer.class);
+ private Session session;
+ private int start;
+ private int end;
+
+ public ASyncProducer(AMQQueue q, int start, int end) throws Exception
+ {
+ this.session = con.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ this._logger.info("Create Consumer of Q1");
+ this.producer = this.session.createProducer(q);
+ this.start = start;
+ this.end = end;
+ }
+
+ public void run()
+ {
+ try
+ {
+ this._logger.info("Starting to send messages");
+ for (int i = start; i < end && !interrupted(); i++)
+ {
+ producer.send(session.createTextMessage(Integer.toString(i)));
+ }
+ this._logger.info("Sent " + (end - start) + " messages");
+ }
+ catch (JMSException e)
+ {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+ TransportConnection.createVMBroker(1);
+
+ _logger.info("Create Connection");
+ con = new AMQConnection(BROKER, "guest", "guest", "OrderingTest", "test");
+ _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"),
+ false, true);
+ _logger.info("Create Consumer of Q");
+ consumer = session.createConsumer(queue);
+ _logger.info("Start Connection");
+ con.start();
+ }
+
+ public void testPausedOrder() throws Exception
+ {
+
+ // Setup initial messages
+ _logger.info("Creating first producer thread");
+ producerThread = new ASyncProducer(queue, 0, NUM_MESSAGES / 2);
+ producerThread.start();
+ // Wait for them to be done
+ producerThread.join();
+
+ // Setup second set of messages to produce while we consume
+ _logger.info("Creating second producer thread");
+ producerThread = new ASyncProducer(queue, NUM_MESSAGES / 2, NUM_MESSAGES);
+ producerThread.start();
+
+ // Start consuming and checking they're in order
+ _logger.info("Consuming messages");
+ for (int i = 0; i < NUM_MESSAGES; i++)
+ {
+ Message msg = consumer.receive(3000);
+ assertNotNull("Message should not be null", msg);
+ assertTrue("Message should be a text message", msg instanceof TextMessage);
+ assertEquals("Message content does not match expected", Integer.toString(i), ((TextMessage) msg).getText());
+ }
+ }
+
+ protected void tearDown() throws Exception
+ {
+ _logger.info("Interuptting producer thread");
+ producerThread.interrupt();
+ _logger.info("Closing connection");
+ con.close();
+
+ TransportConnection.killAllVMBrokers();
+ super.tearDown();
+ }
+
+ public static junit.framework.Test suite()
+ {
+ return new junit.framework.TestSuite(AMQQueueDeferredOrderingTest.class);
+ }
+
+}
diff --git a/Final/java/client/src/test/java/org/apache/qpid/client/DispatcherTest.java b/Final/java/client/src/test/java/org/apache/qpid/client/DispatcherTest.java
new file mode 100644
index 0000000000..7cca22de6c
--- /dev/null
+++ b/Final/java/client/src/test/java/org/apache/qpid/client/DispatcherTest.java
@@ -0,0 +1,252 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ *
+ */
+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 javax.jms.Connection;
+import javax.jms.ConnectionFactory;
+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.naming.Context;
+import javax.naming.spi.InitialContextFactory;
+
+import java.util.Hashtable;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * QPID-293 Setting MessageListener after connection has started can cause messages to be "lost" on a internal delivery queue
+ * <p/>
+ * The message delivery process:
+ * Mina puts a message on _queue in AMQSession and the dispatcher thread take()s
+ * from here and dispatches to the _consumers. If the _consumer doesn't have a message listener set at connection start
+ * then messages are stored on _synchronousQueue (which needs to be > 1 to pass JMS TCK as multiple consumers on a
+ * session can run in any order and a synchronous put/poll will block the dispatcher).
+ * <p/>
+ * 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
+{
+ private static final Logger _logger = LoggerFactory.getLogger(DispatcherTest.class);
+
+ Context _context;
+
+ private static final int MSG_COUNT = 6;
+ private int _receivedCount = 0;
+ private int _receivedCountWhileStopped = 0;
+ private Connection _clientConnection, _producerConnection;
+ private MessageConsumer _consumer;
+ MessageProducer _producer;
+ Session _clientSession, _producerSession;
+
+ private final CountDownLatch _allFirstMessagesSent = new CountDownLatch(1); // all messages Sent Lock
+ private final CountDownLatch _allSecondMessagesSent = new CountDownLatch(1); // all messages Sent Lock
+
+ private volatile boolean _connectionStopped = false;
+
+ 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();
+
+ _clientSession = _clientConnection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ _consumer = _clientSession.createConsumer(queue);
+
+ // Create Producer
+ _producerConnection = ((ConnectionFactory) _context.lookup("connection")).createConnection();
+
+ _producerConnection.start();
+
+ _producerSession = _producerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ _producer = _producerSession.createProducer(queue);
+
+ for (int msg = 0; msg < MSG_COUNT; msg++)
+ {
+ _producer.send(_producerSession.createTextMessage("Message " + msg));
+ }
+ }
+
+ protected void tearDown() throws Exception
+ {
+
+ _clientConnection.close();
+
+ _producerConnection.close();
+ super.tearDown();
+ TransportConnection.killAllVMBrokers();
+ }
+
+ public void testAsynchronousRecieve()
+ {
+ _logger.info("Test Start");
+
+ assertTrue(!((AMQConnection) _clientConnection).started());
+
+ // Set default Message Listener
+ try
+ {
+ _consumer.setMessageListener(new MessageListener()
+ {
+ public void onMessage(Message message)
+ {
+ _logger.info("Client 1 ML 1 Received Message(" + _receivedCount + "):" + message);
+
+ _receivedCount++;
+
+ if (_receivedCount == MSG_COUNT)
+ {
+ _allFirstMessagesSent.countDown();
+ }
+
+ if (_connectionStopped)
+ {
+ _logger.info("Running with Message:" + _receivedCount);
+ }
+
+ if (_connectionStopped && (_allFirstMessagesSent.getCount() == 0))
+ {
+ _receivedCountWhileStopped++;
+ }
+
+ if (_allFirstMessagesSent.getCount() == 0)
+ {
+ if (_receivedCount == (MSG_COUNT * 2))
+ {
+ _allSecondMessagesSent.countDown();
+ }
+ }
+ }
+ });
+
+ assertTrue("Connecion should not be started", !((AMQConnection) _clientConnection).started());
+ _clientConnection.start();
+ }
+ catch (JMSException e)
+ {
+ _logger.error("Error Setting Default ML on consumer1");
+ }
+
+ try
+ {
+ _allFirstMessagesSent.await(1000, TimeUnit.MILLISECONDS);
+ }
+ catch (InterruptedException e)
+ {
+ // do nothing
+ }
+
+ try
+ {
+ assertTrue("Connecion should be started", ((AMQConnection) _clientConnection).started());
+ _clientConnection.stop();
+ _connectionStopped = true;
+ }
+ catch (JMSException e)
+ {
+ _logger.error("Error stopping connection");
+ }
+
+ try
+ {
+ _logger.error("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);
+ }
+
+ try
+ {
+ Thread.sleep(1000);
+ }
+ catch (InterruptedException e)
+ {
+ // ignore
+ }
+
+ try
+ {
+ _logger.info("Restarting connection");
+
+ _connectionStopped = false;
+ _clientConnection.start();
+ }
+ catch (JMSException e)
+ {
+ _logger.error("Error Setting Better ML on consumer1", e);
+ }
+
+ _logger.info("Waiting upto 2 seconds for messages");
+
+ try
+ {
+ _allSecondMessagesSent.await(1000, TimeUnit.MILLISECONDS);
+ }
+ catch (InterruptedException e)
+ {
+ // do nothing
+ }
+
+ assertEquals("Messages not received correctly", 0, _allFirstMessagesSent.getCount());
+ assertEquals("Messages not received correctly", 0, _allSecondMessagesSent.getCount());
+ assertEquals("Client didn't get all messages", MSG_COUNT * 2, _receivedCount);
+ assertEquals("Messages received while stopped is not 0", 0, _receivedCountWhileStopped);
+ }
+
+ public static junit.framework.Test suite()
+ {
+ return new junit.framework.TestSuite(DispatcherTest.class);
+ }
+}
diff --git a/Final/java/client/src/test/java/org/apache/qpid/client/MessageListenerMultiConsumerImmediatePrefetch.java b/Final/java/client/src/test/java/org/apache/qpid/client/MessageListenerMultiConsumerImmediatePrefetch.java
new file mode 100644
index 0000000000..7461f6c200
--- /dev/null
+++ b/Final/java/client/src/test/java/org/apache/qpid/client/MessageListenerMultiConsumerImmediatePrefetch.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.client;
+
+/**
+ * QPID-293 Setting MessageListener after connection has started can cause messages to be "lost" on a internal delivery
+ * queue <p/> The message delivery process: Mina puts a message on _queue in AMQSession and the dispatcher thread
+ * take()s from here and dispatches to the _consumers. If the _consumer1 doesn't have a message listener set at
+ * connection start then messages are stored on _synchronousQueue (which needs to be > 1 to pass JMS TCK as multiple
+ * consumers on a session can run in any order and a synchronous put/poll will block the dispatcher). <p/> 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 MessageListenerMultiConsumerImmediatePrefetch extends MessageListenerMultiConsumerTest
+{
+ protected void setUp() throws Exception
+ {
+ System.setProperty(AMQSession.IMMEDIATE_PREFETCH, "true");
+ super.setUp();
+ }
+
+ public static junit.framework.Test suite()
+ {
+ return new junit.framework.TestSuite(MessageListenerMultiConsumerImmediatePrefetch.class);
+ }
+}
diff --git a/Final/java/client/src/test/java/org/apache/qpid/client/MessageListenerMultiConsumerTest.java b/Final/java/client/src/test/java/org/apache/qpid/client/MessageListenerMultiConsumerTest.java
new file mode 100644
index 0000000000..20632e245f
--- /dev/null
+++ b/Final/java/client/src/test/java/org/apache/qpid/client/MessageListenerMultiConsumerTest.java
@@ -0,0 +1,252 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ *
+ */
+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 javax.jms.Connection;
+import javax.jms.ConnectionFactory;
+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.naming.Context;
+import javax.naming.spi.InitialContextFactory;
+
+import java.util.Hashtable;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * QPID-293 Setting MessageListener after connection has started can cause messages to be "lost" on a internal delivery
+ * queue <p/> The message delivery process: Mina puts a message on _queue in AMQSession and the dispatcher thread
+ * take()s from here and dispatches to the _consumers. If the _consumer1 doesn't have a message listener set at
+ * connection start then messages are stored on _synchronousQueue (which needs to be > 1 to pass JMS TCK as multiple
+ * consumers on a session can run in any order and a synchronous put/poll will block the dispatcher). <p/> 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 MessageListenerMultiConsumerTest extends TestCase
+{
+ private static final Logger _logger = LoggerFactory.getLogger(MessageListenerMultiConsumerTest.class);
+
+ Context _context;
+
+ private static final int MSG_COUNT = 6;
+ private int receivedCount1 = 0;
+ private int receivedCount2 = 0;
+ private Connection _clientConnection;
+ private MessageConsumer _consumer1;
+ private MessageConsumer _consumer2;
+ private Session _clientSession1;
+ private Queue _queue;
+ private final CountDownLatch _allMessagesSent = new CountDownLatch(2); // all messages Sent Lock
+
+ 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", "direct://amq.direct//" + this.getClass().getName());
+
+ _context = factory.getInitialContext(env);
+
+ _queue = (Queue) _context.lookup("queue");
+
+ // Create Client 1
+ _clientConnection = ((ConnectionFactory) _context.lookup("connection")).createConnection();
+
+ _clientConnection.start();
+
+ _clientSession1 = _clientConnection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ _consumer1 = _clientSession1.createConsumer(_queue);
+
+ // Create Client 2
+ Session clientSession2 = _clientConnection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ _consumer2 = clientSession2.createConsumer(_queue);
+
+ // Create Producer
+ Connection producerConnection = ((ConnectionFactory) _context.lookup("connection")).createConnection();
+
+ producerConnection.start();
+
+ Session producerSession = producerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ MessageProducer producer = producerSession.createProducer(_queue);
+
+ for (int msg = 0; msg < MSG_COUNT; msg++)
+ {
+ producer.send(producerSession.createTextMessage("Message " + msg));
+ }
+
+ producerConnection.close();
+
+ }
+
+ protected void tearDown() throws Exception
+ {
+ _clientConnection.close();
+
+ super.tearDown();
+ TransportConnection.killAllVMBrokers();
+ }
+
+ public void testRecieveInterleaved() throws Exception
+ {
+ int msg = 0;
+ int MAX_LOOPS = MSG_COUNT * 2;
+ for (int loops = 0; (msg < MSG_COUNT) || (loops < MAX_LOOPS); loops++)
+ {
+
+ if (_consumer1.receive(100) != null)
+ {
+ msg++;
+ }
+
+ if (_consumer2.receive(100) != null)
+ {
+ msg++;
+ }
+ }
+
+ assertEquals("Not all messages received.", MSG_COUNT, msg);
+ }
+
+ public void testAsynchronousRecieve() throws Exception
+ {
+ _consumer1.setMessageListener(new MessageListener()
+ {
+ public void onMessage(Message message)
+ {
+ _logger.info("Client 1 Received Message(" + receivedCount1 + "):" + message);
+
+ receivedCount1++;
+
+ if (receivedCount1 == (MSG_COUNT / 2))
+ {
+ _allMessagesSent.countDown();
+ }
+
+ }
+ });
+
+ _consumer2.setMessageListener(new MessageListener()
+ {
+ public void onMessage(Message message)
+ {
+ _logger.info("Client 2 Received Message(" + receivedCount2 + "):" + message);
+
+ receivedCount2++;
+ if (receivedCount2 == (MSG_COUNT / 2))
+ {
+ _allMessagesSent.countDown();
+ }
+ }
+ });
+
+ _logger.info("Waiting upto 2 seconds for messages");
+
+ try
+ {
+ _allMessagesSent.await(4000, TimeUnit.MILLISECONDS);
+ }
+ catch (InterruptedException e)
+ {
+ // do nothing
+ }
+
+ assertEquals(MSG_COUNT, receivedCount1 + receivedCount2);
+ }
+
+ public void testRecieveC2Only() throws Exception
+ {
+ if (
+ !Boolean.parseBoolean(
+ System.getProperties().getProperty(AMQSession.IMMEDIATE_PREFETCH,
+ AMQSession.IMMEDIATE_PREFETCH_DEFAULT)))
+ {
+ _logger.info("Performing Receive only on C2");
+ for (int msg = 0; msg < MSG_COUNT; msg++)
+ {
+ assertTrue(MSG_COUNT + " msg should be received. Only received:" + msg, _consumer2.receive(1000) != null);
+ }
+ }
+ }
+
+ public void testRecieveBoth() throws Exception
+ {
+ if (
+ !Boolean.parseBoolean(
+ System.getProperties().getProperty(AMQSession.IMMEDIATE_PREFETCH,
+ AMQSession.IMMEDIATE_PREFETCH_DEFAULT)))
+ {
+ _logger.info("Performing Receive only with two consumers on one session ");
+
+ MessageConsumer consumer2 = _clientSession1.createConsumer(_queue);
+
+ for (int msg = 0; msg < (MSG_COUNT / 2); msg++)
+ {
+
+ assertTrue(_consumer1.receive() != null);
+ }
+
+ for (int msg = 0; msg < (MSG_COUNT / 2); msg++)
+ {
+ assertTrue(consumer2.receive() != null);
+ }
+ }
+ else
+ {
+ _logger.info("Performing Receive only on both C1 and C2");
+
+ for (int msg = 0; msg < (MSG_COUNT / 2); msg++)
+ {
+
+ assertTrue(_consumer1.receive() != null);
+ }
+
+ for (int msg = 0; msg < (MSG_COUNT / 2); msg++)
+ {
+ assertTrue(_consumer2.receive() != null);
+ }
+ }
+ }
+
+ public static junit.framework.Test suite()
+ {
+ return new junit.framework.TestSuite(MessageListenerMultiConsumerTest.class);
+ }
+}
diff --git a/Final/java/client/src/test/java/org/apache/qpid/client/MessageListenerTest.java b/Final/java/client/src/test/java/org/apache/qpid/client/MessageListenerTest.java
new file mode 100644
index 0000000000..87630fad5b
--- /dev/null
+++ b/Final/java/client/src/test/java/org/apache/qpid/client/MessageListenerTest.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.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 javax.jms.Connection;
+import javax.jms.ConnectionFactory;
+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.naming.Context;
+import javax.naming.spi.InitialContextFactory;
+
+import java.util.Hashtable;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * QPID-293 Setting MessageListener after connection has started can cause messages to be "lost" on a internal delivery
+ * queue <p/> The message delivery process: Mina puts a message on _queue in AMQSession and the dispatcher thread
+ * take()s from here and dispatches to the _consumers. If the _consumer doesn't have a message listener set at
+ * connection start then messages are stored on _synchronousQueue (which needs to be > 1 to pass JMS TCK as multiple
+ * consumers on a session can run in any order and a synchronous put/poll will block the dispatcher). <p/> 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 MessageListenerTest extends TestCase implements MessageListener
+{
+ private static final Logger _logger = LoggerFactory.getLogger(MessageListenerTest.class);
+
+ Context _context;
+
+ private static final int MSG_COUNT = 5;
+ private int receivedCount = 0;
+ private MessageConsumer _consumer;
+ private Connection _clientConnection;
+ private CountDownLatch _awaitMessages = new CountDownLatch(MSG_COUNT);
+ private static final String BROKER = "vm://:1";
+ private static final String VHOST = "test";
+
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+ if (BROKER.contains("vm://"))
+ {
+ TransportConnection.createVMBroker(1);
+ }
+
+ InitialContextFactory factory = new PropertiesFileInitialContextFactory();
+
+ Hashtable<String, String> env = new Hashtable<String, String>();
+
+ env.put("connectionfactory.connection", "amqp://guest:guest@MLT_ID/" + VHOST + "?brokerlist='" + BROKER + "'");
+ env.put("queue.queue", "MessageListenerTest");
+
+ _context = factory.getInitialContext(env);
+
+ Queue queue = (Queue) _context.lookup("queue");
+
+ // Create Client
+ _clientConnection = ((ConnectionFactory) _context.lookup("connection")).createConnection();
+
+ _clientConnection.start();
+
+ Session clientSession = _clientConnection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ _consumer = clientSession.createConsumer(queue);
+
+ // Create Producer
+
+ Connection producerConnection = ((ConnectionFactory) _context.lookup("connection")).createConnection();
+
+ producerConnection.start();
+
+ Session producerSession = producerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ MessageProducer producer = producerSession.createProducer(queue);
+
+ for (int msg = 0; msg < MSG_COUNT; msg++)
+ {
+ producer.send(producerSession.createTextMessage("Message " + msg));
+ }
+
+ producerConnection.close();
+
+ }
+
+ protected void tearDown() throws Exception
+ {
+ _clientConnection.close();
+
+ super.tearDown();
+ if (BROKER.contains("vm://"))
+ {
+ TransportConnection.killAllVMBrokers();
+ }
+ }
+
+ public void testSynchronousRecieve() throws Exception
+ {
+ for (int msg = 0; msg < MSG_COUNT; msg++)
+ {
+ assertTrue(_consumer.receive(2000) != null);
+ }
+ }
+
+ public void testAsynchronousRecieve() throws Exception
+ {
+ _consumer.setMessageListener(this);
+
+ _logger.info("Waiting 3 seconds for messages");
+
+ try
+ {
+ _awaitMessages.await(3000, TimeUnit.MILLISECONDS);
+ }
+ catch (InterruptedException e)
+ {
+ // do nothing
+ }
+ // Should have recieved all async messages
+ assertEquals(MSG_COUNT, receivedCount);
+
+ }
+
+ public void testRecieveTheUseMessageListener() throws Exception
+ {
+
+ _logger.error("Test disabled as initial receive is not called first");
+ // Perform initial receive to start connection
+ // assertTrue(_consumer.receive(2000) != null);
+ // receivedCount++;
+
+ // Sleep to ensure remaining 4 msgs end up on _synchronousQueue
+ // Thread.sleep(1000);
+
+ // Set the message listener and wait for the messages to come in.
+ _consumer.setMessageListener(this);
+
+ _logger.info("Waiting 3 seconds for messages");
+
+ try
+ {
+ _awaitMessages.await(3000, TimeUnit.MILLISECONDS);
+ }
+ catch (InterruptedException e)
+ {
+ // do nothing
+ }
+ // Should have recieved all async messages
+ assertEquals(MSG_COUNT, receivedCount);
+
+ }
+
+ public void onMessage(Message message)
+ {
+ _logger.info("Received Message(" + receivedCount + "):" + message);
+
+ receivedCount++;
+ _awaitMessages.countDown();
+ }
+
+ public static junit.framework.Test suite()
+ {
+ return new junit.framework.TestSuite(MessageListenerTest.class);
+ }
+}
diff --git a/Final/java/client/src/test/java/org/apache/qpid/client/ResetMessageListenerTest.java b/Final/java/client/src/test/java/org/apache/qpid/client/ResetMessageListenerTest.java
new file mode 100644
index 0000000000..21f3e273aa
--- /dev/null
+++ b/Final/java/client/src/test/java/org/apache/qpid/client/ResetMessageListenerTest.java
@@ -0,0 +1,277 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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 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 javax.jms.Connection;
+import javax.jms.ConnectionFactory;
+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.naming.Context;
+import javax.naming.spi.InitialContextFactory;
+
+import java.util.Hashtable;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * QPID-293 Setting MessageListener after connection has started can cause messages to be "lost" on a internal delivery
+ * queue <p/> The message delivery process: Mina puts a message on _queue in AMQSession and the dispatcher thread
+ * take()s from here and dispatches to the _consumers. If the _consumer1 doesn't have a message listener set at
+ * connection start then messages are stored on _synchronousQueue (which needs to be > 1 to pass JMS TCK as multiple
+ * consumers on a session can run in any order and a synchronous put/poll will block the dispatcher). <p/> 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 ResetMessageListenerTest extends TestCase
+{
+ private static final Logger _logger = LoggerFactory.getLogger(ResetMessageListenerTest.class);
+
+ 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 String oldImmediatePrefetch;
+
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+ TransportConnection.createVMBroker(1);
+
+ oldImmediatePrefetch = System.getProperty(AMQSession.IMMEDIATE_PREFETCH);
+ System.setProperty(AMQSession.IMMEDIATE_PREFETCH, "true");
+
+ 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", "direct://amq.direct//ResetMessageListenerTest");
+
+ _context = factory.getInitialContext(env);
+
+ Queue queue = (Queue) _context.lookup("queue");
+
+ // Create Client 1
+ _clientConnection = ((ConnectionFactory) _context.lookup("connection")).createConnection();
+
+ _clientSession = _clientConnection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ _consumer1 = _clientSession.createConsumer(queue);
+
+ // Create Client 2 on same session
+ _consumer2 = _clientSession.createConsumer(queue);
+
+ // Create Producer
+ _producerConnection = ((ConnectionFactory) _context.lookup("connection")).createConnection();
+
+ _producerConnection.start();
+
+ _producerSession = _producerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ _producer = _producerSession.createProducer(queue);
+
+ for (int msg = 0; msg < MSG_COUNT; msg++)
+ {
+ _producer.send(_producerSession.createTextMessage("Message " + msg));
+ }
+
+ }
+
+ protected void tearDown() throws Exception
+ {
+ _clientConnection.close();
+ _producerConnection.close();
+
+ super.tearDown();
+ if (oldImmediatePrefetch == null)
+ {
+ oldImmediatePrefetch = AMQSession.IMMEDIATE_PREFETCH_DEFAULT;
+ }
+ System.setProperty(AMQSession.IMMEDIATE_PREFETCH, oldImmediatePrefetch);
+ TransportConnection.killAllVMBrokers();
+ }
+
+ public void testAsynchronousRecieve()
+ {
+
+ _logger.info("Test Start");
+
+ // Set default Message Listener
+ try
+ {
+ _consumer1.setMessageListener(new MessageListener()
+ {
+ public void onMessage(Message message)
+ {
+ _logger.info("Client 1 ML 1 Received Message(" + receivedCount1ML1 + "):" + message);
+
+ receivedCount1ML1++;
+ if (receivedCount1ML1 == (MSG_COUNT / 2))
+ {
+ _allFirstMessagesSent.countDown();
+ }
+ }
+ });
+ }
+ catch (JMSException e)
+ {
+ _logger.error("Error Setting Default ML on consumer1");
+ }
+
+ try
+ {
+ _consumer2.setMessageListener(new MessageListener()
+ {
+ public void onMessage(Message message)
+ {
+ _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();
+ }
+ }
+ });
+
+ _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");
+
+ 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);
+ }
+
+ public static junit.framework.Test suite()
+ {
+ return new junit.framework.TestSuite(ResetMessageListenerTest.class);
+ }
+}
diff --git a/Final/java/client/src/test/java/org/apache/qpid/client/SpecificMethodFrameListenerTest.java b/Final/java/client/src/test/java/org/apache/qpid/client/SpecificMethodFrameListenerTest.java
new file mode 100644
index 0000000000..4cffcecf8a
--- /dev/null
+++ b/Final/java/client/src/test/java/org/apache/qpid/client/SpecificMethodFrameListenerTest.java
@@ -0,0 +1,71 @@
+package org.apache.qpid.framing;
+
+import junit.framework.TestCase;
+import org.apache.qpid.client.state.listener.SpecificMethodFrameListener;
+import org.apache.mina.common.ByteBuffer;
+
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT 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 class SpecificMethodFrameListenerTest extends TestCase
+{
+
+ SpecificMethodFrameListener close1a = new SpecificMethodFrameListener(1, ChannelCloseOkBody.class);
+ SpecificMethodFrameListener close1b = new SpecificMethodFrameListener(1, ChannelCloseOkBody.class);
+ SpecificMethodFrameListener close2 = new SpecificMethodFrameListener(2, ChannelCloseOkBody.class);
+ SpecificMethodFrameListener open1a = new SpecificMethodFrameListener(1, ChannelOpenOkBody.class);
+ SpecificMethodFrameListener open1b = new SpecificMethodFrameListener(1, ChannelOpenOkBody.class);
+
+ public void testEquals()
+ {
+ //Check that the the same objects are equal
+ assertEquals("ChannelCloseOKBody a should equal a", close1a, close1a);
+ assertEquals("ChannelOpenOkBody a should equal a", open1a, open1a);
+
+ //check that the same values in differnt objects are equal
+ assertEquals("ChannelCloseOKBody b should equal a", close1b, close1a);
+ assertEquals("ChannelCloseOKBody a should equal b", close1a, close1b);
+ assertEquals("ChannelOpenOkBody a should equal b", open1a, open1b);
+ assertEquals("ChannelOpenOkBody a should equal b", open1a, open1b);
+
+ //Chec that different values fail
+ //Different channels
+ assertFalse("ChannelCloseOKBody channel 1 should NOT equal channel 2", close1a.equals(close2));
+ assertFalse("ChannelCloseOKBody channel 1 should NOT equal channel 2", close2.equals(close1a));
+
+ //Different Bodies
+ assertFalse("ChannelCloseOKBody should not equal ChannelOpenOkBody", close1a.equals(open1a));
+ assertFalse("ChannelOpenOkBody should not equal ChannelCloseOKBody", open1a.equals(close1a));
+ }
+
+ public void testProcessMethod() throws AMQFrameDecodingException
+ {
+ ChannelCloseOkBody ccob = (ChannelCloseOkBody) ChannelCloseOkBody.getFactory().newInstance((byte) 8, (byte) 0, ByteBuffer.allocate(0), 0);
+ ChannelOpenOkBody coob = (ChannelOpenOkBody) ChannelOpenOkBody.getFactory().newInstance((byte) 8, (byte) 0, ByteBuffer.allocate(0), 0);
+
+ assertTrue("This SpecificMethodFrameListener should process a ChannelCloseOkBody", close1a.processMethod(1, ccob));
+ assertFalse("This SpecificMethodFrameListener should NOT process a ChannelOpenOkBody", close1a.processMethod(1, coob));
+
+
+
+
+ }
+}
diff --git a/Final/java/client/src/test/java/org/apache/qpid/client/message/NonQpidObjectMessage.java b/Final/java/client/src/test/java/org/apache/qpid/client/message/NonQpidObjectMessage.java
new file mode 100644
index 0000000000..60a26c8e62
--- /dev/null
+++ b/Final/java/client/src/test/java/org/apache/qpid/client/message/NonQpidObjectMessage.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.client.message;
+
+import java.io.Serializable;
+import java.util.Enumeration;
+
+import javax.jms.Destination;
+import javax.jms.JMSException;
+import javax.jms.ObjectMessage;
+
+public class NonQpidObjectMessage implements ObjectMessage {
+
+ private JMSObjectMessage _realMessage;
+ private String _contentString;
+
+ /**
+ * Allows us to construct a JMS message which
+ * does not inherit from the Qpid message superclasses
+ * and expand our unit testing of MessageConverter et al
+ */
+ public NonQpidObjectMessage()
+ {
+ _realMessage = new JMSObjectMessage();
+ }
+
+ public String getJMSMessageID() throws JMSException {
+ return _realMessage.getJMSMessageID();
+ }
+
+ public void setJMSMessageID(String string) throws JMSException {
+ _realMessage.setJMSMessageID(string);
+ }
+
+ public long getJMSTimestamp() throws JMSException {
+ return _realMessage.getJMSTimestamp();
+ }
+
+ public void setJMSTimestamp(long l) throws JMSException {
+ _realMessage.setJMSTimestamp(l);
+ }
+
+ public byte[] getJMSCorrelationIDAsBytes() throws JMSException {
+ return _realMessage.getJMSCorrelationIDAsBytes();
+ }
+
+ public void setJMSCorrelationIDAsBytes(byte[] bytes) throws JMSException {
+ _realMessage.setJMSCorrelationIDAsBytes(bytes);
+ }
+
+ public void setJMSCorrelationID(String string) throws JMSException {
+ _realMessage.setJMSCorrelationID(string);
+ }
+
+ public String getJMSCorrelationID() throws JMSException {
+ return _realMessage.getJMSCorrelationID();
+ }
+
+ public Destination getJMSReplyTo() throws JMSException {
+ return _realMessage.getJMSReplyTo();
+ }
+
+ public void setJMSReplyTo(Destination destination) throws JMSException {
+ _realMessage.setJMSReplyTo(destination);
+ }
+
+ public Destination getJMSDestination() throws JMSException {
+ return _realMessage.getJMSDestination();
+ }
+
+ public void setJMSDestination(Destination destination) throws JMSException {
+ _realMessage.setJMSDestination(destination);
+ }
+
+ public int getJMSDeliveryMode() throws JMSException {
+ return _realMessage.getJMSDeliveryMode();
+ }
+
+ public void setJMSDeliveryMode(int i) throws JMSException {
+ _realMessage.setJMSDeliveryMode(i);
+ }
+
+ public boolean getJMSRedelivered() throws JMSException {
+ return _realMessage.getJMSRedelivered();
+ }
+
+ public void setJMSRedelivered(boolean b) throws JMSException {
+ _realMessage.setJMSRedelivered(b);
+ }
+
+ public String getJMSType() throws JMSException {
+ return _realMessage.getJMSType();
+ }
+
+ public void setJMSType(String string) throws JMSException {
+ _realMessage.setJMSType(string);
+ }
+
+ public long getJMSExpiration() throws JMSException {
+ return _realMessage.getJMSExpiration();
+ }
+
+ public void setJMSExpiration(long l) throws JMSException {
+ _realMessage.setJMSExpiration(l);
+ }
+
+ public int getJMSPriority() throws JMSException {
+ return _realMessage.getJMSPriority();
+ }
+
+ public void setJMSPriority(int i) throws JMSException {
+ _realMessage.setJMSPriority(i);
+ }
+
+ public void clearProperties() throws JMSException {
+ _realMessage.clearProperties();
+ }
+
+ public boolean propertyExists(String string) throws JMSException {
+ return _realMessage.propertyExists(string);
+ }
+
+ public boolean getBooleanProperty(String string) throws JMSException {
+ return _realMessage.getBooleanProperty(string);
+ }
+
+ public byte getByteProperty(String string) throws JMSException {
+ return _realMessage.getByteProperty(string);
+ }
+
+ public short getShortProperty(String string) throws JMSException {
+ return _realMessage.getShortProperty(string);
+ }
+
+ public int getIntProperty(String string) throws JMSException {
+ return _realMessage.getIntProperty(string);
+ }
+
+ public long getLongProperty(String string) throws JMSException {
+ return _realMessage.getLongProperty(string);
+ }
+
+ public float getFloatProperty(String string) throws JMSException {
+ return _realMessage.getFloatProperty(string);
+ }
+
+ public double getDoubleProperty(String string) throws JMSException {
+ return _realMessage.getDoubleProperty(string);
+ }
+
+ public String getStringProperty(String string) throws JMSException {
+ return _realMessage.getStringProperty(string);
+ }
+
+ public Object getObjectProperty(String string) throws JMSException {
+ return _realMessage.getObjectProperty(string);
+ }
+
+ public Enumeration getPropertyNames() throws JMSException {
+ return _realMessage.getPropertyNames();
+ }
+
+ public void setBooleanProperty(String string, boolean b) throws JMSException {
+ _realMessage.setBooleanProperty(string,b);
+ }
+
+ public void setByteProperty(String string, byte b) throws JMSException {
+ _realMessage.setByteProperty(string,b);
+ }
+
+ public void setShortProperty(String string, short i) throws JMSException {
+ _realMessage.setShortProperty(string,i);
+ }
+
+ public void setIntProperty(String string, int i) throws JMSException {
+ _realMessage.setIntProperty(string,i);
+ }
+
+ public void setLongProperty(String string, long l) throws JMSException {
+ _realMessage.setLongProperty(string,l);
+ }
+
+ public void setFloatProperty(String string, float v) throws JMSException {
+ _realMessage.setFloatProperty(string,v);
+ }
+
+ public void setDoubleProperty(String string, double v) throws JMSException {
+ _realMessage.setDoubleProperty(string,v);
+ }
+
+ public void setStringProperty(String string, String string1) throws JMSException {
+ _realMessage.setStringProperty(string,string1);
+ }
+
+ public void setObjectProperty(String string, Object object) throws JMSException {
+ _realMessage.setObjectProperty(string,object);
+ }
+
+ public void acknowledge() throws JMSException {
+ _realMessage.acknowledge();
+ }
+
+ public void clearBody() throws JMSException {
+ _realMessage.clearBody();
+ }
+
+ public void setObject(Serializable serializable) throws JMSException {
+ if (serializable instanceof String)
+ {
+ _contentString = (String)serializable;
+ }
+ }
+
+ public Serializable getObject() throws JMSException {
+ return _contentString; }
+}
diff --git a/Final/java/client/src/test/java/org/apache/qpid/client/message/TestMessageHelper.java b/Final/java/client/src/test/java/org/apache/qpid/client/message/TestMessageHelper.java
new file mode 100644
index 0000000000..9b477c19e2
--- /dev/null
+++ b/Final/java/client/src/test/java/org/apache/qpid/client/message/TestMessageHelper.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.client.message;
+
+import javax.jms.JMSException;
+
+public class TestMessageHelper
+{
+ public static JMSTextMessage newJMSTextMessage() throws JMSException
+ {
+ return new JMSTextMessage();
+ }
+
+ public static JMSBytesMessage newJMSBytesMessage() throws JMSException
+ {
+ return new JMSBytesMessage();
+ }
+
+ public static JMSMapMessage newJMSMapMessage() throws JMSException
+ {
+ return new JMSMapMessage();
+ }
+
+ public static JMSStreamMessage newJMSStreamMessage()
+ {
+ return new JMSStreamMessage();
+ }
+}
diff --git a/Final/java/client/src/test/java/org/apache/qpid/test/unit/ack/RecoverTest.java b/Final/java/client/src/test/java/org/apache/qpid/test/unit/ack/RecoverTest.java
new file mode 100644
index 0000000000..b6f46b4acc
--- /dev/null
+++ b/Final/java/client/src/test/java/org/apache/qpid/test/unit/ack/RecoverTest.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.test.unit.ack;
+
+import junit.framework.TestCase;
+
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.client.AMQQueue;
+import org.apache.qpid.client.transport.TransportConnection;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.jms.Session;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+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.TextMessage;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class RecoverTest extends TestCase
+{
+ private static final Logger _logger = LoggerFactory.getLogger(RecoverTest.class);
+
+ private Exception _error;
+ private AtomicInteger count;
+
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+ TransportConnection.createVMBroker(1);
+ _error = null;
+ count = new AtomicInteger();
+ }
+
+ protected void tearDown() throws Exception
+ {
+ super.tearDown();
+ TransportConnection.killAllVMBrokers();
+ count = null;
+ }
+
+ public void testRecoverResendsMsgs() throws Exception
+ {
+ AMQConnection con = new AMQConnection("vm://:1", "guest", "guest", "consumer1", "test");
+
+ 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
+
+ AMQConnection con2 = new AMQConnection("vm://:1", "guest", "guest", "producer1", "test");
+ Session producerSession = con2.createSession(false, Session.CLIENT_ACKNOWLEDGE);
+ MessageProducer producer = producerSession.createProducer(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();
+
+ _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());
+
+ tm = (TextMessage) consumer.receive(3000);
+ assertEquals("msg3", tm.getText());
+
+ tm = (TextMessage) consumer.receive(3000);
+ assertEquals("msg4", tm.getText());
+
+ _logger.info("Received redelivery of three messages. Acknowledging last message");
+ tm.acknowledge();
+
+ _logger.info("Calling acknowledge with no outstanding messages");
+ // 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();
+ }
+
+ public void testRecoverResendsMsgsAckOnEarlier() throws Exception
+ {
+ AMQConnection con = new AMQConnection("vm://:1", "guest", "guest", "consumer1", "test");
+
+ 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
+
+ AMQConnection con2 = new AMQConnection("vm://:1", "guest", "guest", "producer1", "test");
+ Session producerSession = con2.createSession(false, Session.CLIENT_ACKNOWLEDGE);
+ MessageProducer producer = producerSession.createProducer(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();
+
+ _logger.info("Starting connection");
+ con.start();
+ TextMessage tm = (TextMessage) consumer.receive();
+ consumer.receive();
+ tm.acknowledge();
+ _logger.info("Received 2 messages, acknowledge() first message, should acknowledge both");
+
+ 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());
+
+ TextMessage tm4 = (TextMessage) consumer.receive(3000);
+ assertEquals("msg4", tm4.getText());
+
+ _logger.info("Received redelivery of two messages. calling acknolwedgeThis() first of those message");
+ ((org.apache.qpid.jms.Message) tm3).acknowledgeThis();
+
+ _logger.info("Calling recover");
+ // all acked so no messages to be delivered
+ consumerSession.recover();
+
+ tm4 = (TextMessage) consumer.receive(3000);
+ assertEquals("msg4", tm4.getText());
+ ((org.apache.qpid.jms.Message) tm4).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();
+ }
+
+ public void testAcknowledgePerConsumer() throws Exception
+ {
+ AMQConnection con = new AMQConnection("vm://:1", "guest", "guest", "consumer1", "test");
+
+ Session consumerSession = con.createSession(false, Session.CLIENT_ACKNOWLEDGE);
+ Queue queue =
+ 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);
+ MessageConsumer consumer = consumerSession.createConsumer(queue);
+ MessageConsumer consumer2 = consumerSession.createConsumer(queue2);
+
+ AMQConnection con2 = new AMQConnection("vm://:1", "guest", "guest", "producer1", "test");
+ Session producerSession = con2.createSession(false, Session.CLIENT_ACKNOWLEDGE);
+ MessageProducer producer = producerSession.createProducer(queue);
+ MessageProducer producer2 = producerSession.createProducer(queue2);
+
+ producer.send(producerSession.createTextMessage("msg1"));
+ producer2.send(producerSession.createTextMessage("msg2"));
+
+ con2.close();
+
+ _logger.info("Starting connection");
+ con.start();
+
+ TextMessage tm2 = (TextMessage) consumer2.receive();
+ assertNotNull(tm2);
+ assertEquals("msg2", tm2.getText());
+
+ tm2.acknowledge();
+
+ consumerSession.recover();
+
+ TextMessage tm1 = (TextMessage) consumer.receive(2000);
+ assertNotNull(tm1);
+ assertEquals("msg1", tm1.getText());
+
+ con.close();
+
+ }
+
+ public void testRecoverInAutoAckListener() throws Exception
+ {
+ AMQConnection con = new AMQConnection("vm://:1", "guest", "guest", "consumer1", "test");
+
+ final Session consumerSession = con.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ Queue queue =
+ 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"));
+
+ final Object lock = new Object();
+
+ consumer.setMessageListener(new MessageListener()
+ {
+
+ public void onMessage(Message message)
+ {
+ try
+ {
+ count.incrementAndGet();
+ if (count.get() == 1)
+ {
+ if (message.getJMSRedelivered())
+ {
+ setError(
+ new Exception("Message marked as redilvered on what should be first delivery attempt"));
+ }
+
+ consumerSession.recover();
+ }
+ else if (count.get() == 2)
+ {
+ if (!message.getJMSRedelivered())
+ {
+ 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);
+ }
+ }
+ catch (JMSException e)
+ {
+ _logger.error("Error recovering session: " + e, e);
+ setError(e);
+ }
+
+ synchronized (lock)
+ {
+ lock.notify();
+ }
+ }
+ });
+
+ con.start();
+
+ long waitTime = 300000L;
+ long waitUntilTime = System.currentTimeMillis() + waitTime;
+
+ synchronized (lock)
+ {
+ while ((count.get() <= 1) && (waitTime > 0))
+ {
+ lock.wait(waitTime);
+ if (count.get() <= 1)
+ {
+ waitTime = waitUntilTime - System.currentTimeMillis();
+ }
+ }
+ }
+
+ Thread.sleep(1000);
+
+ if (count.get() != 2)
+ {
+ System.err.println("Count != 2 : " + count);
+ }
+
+ assertTrue(count.get() == 2);
+
+ con.close();
+
+ if (_error != null)
+ {
+ throw _error;
+ }
+ }
+
+ private void setError(Exception e)
+ {
+ _error = e;
+ }
+
+ public static junit.framework.Test suite()
+ {
+ return new junit.framework.TestSuite(RecoverTest.class);
+ }
+}
diff --git a/Final/java/client/src/test/java/org/apache/qpid/test/unit/basic/BytesMessageTest.java b/Final/java/client/src/test/java/org/apache/qpid/test/unit/basic/BytesMessageTest.java
new file mode 100644
index 0000000000..da1b46ee2c
--- /dev/null
+++ b/Final/java/client/src/test/java/org/apache/qpid/test/unit/basic/BytesMessageTest.java
@@ -0,0 +1,288 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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 junit.framework.Assert;
+import junit.framework.TestCase;
+
+import org.apache.mina.common.ByteBuffer;
+
+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.message.JMSBytesMessage;
+import org.apache.qpid.testutil.VMBrokerSetup;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.jms.BytesMessage;
+import javax.jms.Connection;
+import javax.jms.Destination;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageListener;
+import javax.jms.MessageNotReadableException;
+import javax.jms.MessageNotWriteableException;
+import javax.jms.MessageProducer;
+import javax.jms.Session;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+public class BytesMessageTest extends TestCase implements MessageListener
+{
+ private static final Logger _logger = LoggerFactory.getLogger(BytesMessageTest.class);
+
+ private Connection _connection;
+ private Destination _destination;
+ private Session _session;
+ private final List<JMSBytesMessage> received = new ArrayList<JMSBytesMessage>();
+ private final List<byte[]> messages = new ArrayList<byte[]>();
+ private int _count = 100;
+ public String _connectionString = "vm://:1";
+
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+ init(new AMQConnection(_connectionString, "guest", "guest", randomize("Client"), "test"));
+ }
+
+ protected void tearDown() throws Exception
+ {
+ super.tearDown();
+ }
+
+ void init(AMQConnection connection) throws Exception
+ {
+ init(connection, new AMQQueue(connection, randomize("BytesMessageTest"), true));
+ }
+
+ void init(AMQConnection connection, AMQDestination destination) throws Exception
+ {
+ _connection = connection;
+ _destination = destination;
+ _session = connection.createSession(false, AMQSession.NO_ACKNOWLEDGE);
+
+ // Set up a slow consumer.
+ _session.createConsumer(destination).setMessageListener(this);
+ connection.start();
+ }
+
+ public void test() throws Exception
+ {
+ try
+ {
+ send(_count);
+ waitFor(_count);
+ check();
+ _logger.info("Completed without failure");
+ }
+ finally
+ {
+ _connection.close();
+ }
+ }
+
+ void send(int count) throws JMSException
+ {
+ // create a publisher
+ MessageProducer producer = _session.createProducer(_destination);
+ for (int i = 0; i < count; i++)
+ {
+ BytesMessage msg = _session.createBytesMessage();
+
+ try
+ {
+ msg.readFloat();
+ Assert.fail("Message should not be readable");
+ }
+ catch (MessageNotReadableException mnwe)
+ {
+ // normal execution
+ }
+
+ byte[] data = ("Message " + i).getBytes();
+ msg.writeBytes(data);
+ messages.add(data);
+ producer.send(msg);
+ }
+ }
+
+ void waitFor(int count) throws InterruptedException
+ {
+ synchronized (received)
+ {
+ while (received.size() < count)
+ {
+ received.wait();
+ }
+ }
+ }
+
+ void check() throws JMSException
+ {
+ List<byte[]> actual = new ArrayList<byte[]>();
+ for (JMSBytesMessage m : received)
+ {
+ ByteBuffer buffer = m.getData();
+ byte[] data = new byte[buffer.remaining()];
+ buffer.get(data);
+ actual.add(data);
+
+ // Check Body Write Status
+ try
+ {
+ m.writeBoolean(true);
+ Assert.fail("Message should not be writeable");
+ }
+ catch (MessageNotWriteableException mnwe)
+ {
+ // normal execution
+ }
+
+ m.clearBody();
+
+ try
+ {
+ m.writeBoolean(true);
+ }
+ catch (MessageNotWriteableException mnwe)
+ {
+ Assert.fail("Message should be writeable");
+ }
+
+ // Check property write status
+ try
+ {
+ m.setStringProperty("test", "test");
+ Assert.fail("Message should not be writeable");
+ }
+ catch (MessageNotWriteableException mnwe)
+ {
+ // normal execution
+ }
+
+ m.clearProperties();
+
+ try
+ {
+ m.setStringProperty("test", "test");
+ }
+ catch (MessageNotWriteableException mnwe)
+ {
+ Assert.fail("Message should be writeable");
+ }
+
+ }
+
+ assertEqual(messages.iterator(), actual.iterator());
+ }
+
+ private static void assertEqual(Iterator expected, Iterator actual)
+ {
+ List<String> errors = new ArrayList<String>();
+ while (expected.hasNext() && actual.hasNext())
+ {
+ try
+ {
+ assertEquivalent((byte[]) expected.next(), (byte[]) actual.next());
+ }
+ catch (Exception e)
+ {
+ errors.add(e.getMessage());
+ }
+ }
+ while (expected.hasNext())
+ {
+ errors.add("Expected " + expected.next() + " but no more actual values.");
+ }
+ while (actual.hasNext())
+ {
+ errors.add("Found " + actual.next() + " but no more expected values.");
+ }
+
+ if (!errors.isEmpty())
+ {
+ throw new RuntimeException(errors.toString());
+ }
+ }
+
+ private static void assertEquivalent(byte[] expected, byte[] actual)
+ {
+ if (expected.length != actual.length)
+ {
+ throw new RuntimeException("Expected length " + expected.length + " got " + actual.length);
+ }
+
+ for (int i = 0; i < expected.length; i++)
+ {
+ if (expected[i] != actual[i])
+ {
+ throw new RuntimeException("Failed on byte " + i + " of " + expected.length);
+ }
+ }
+ }
+
+ public void onMessage(Message message)
+ {
+ synchronized (received)
+ {
+ received.add((JMSBytesMessage) message);
+ received.notify();
+ }
+ }
+
+ private static String randomize(String in)
+ {
+ return in + System.currentTimeMillis();
+ }
+
+ public static void main(String[] argv) throws Exception
+ {
+ final String connectionString;
+ final int count;
+ if (argv.length == 0)
+ {
+ connectionString = "vm://:1";
+ count = 100;
+ }
+ else
+ {
+ connectionString = argv[0];
+ count = Integer.parseInt(argv[1]);
+ }
+
+ System.out.println("connectionString = " + connectionString);
+ System.out.println("count = " + count);
+
+ BytesMessageTest test = new BytesMessageTest();
+ test._connectionString = connectionString;
+ test._count = count;
+ test.test();
+ }
+
+ public static junit.framework.Test suite()
+ {
+ return new VMBrokerSetup(new junit.framework.TestSuite(BytesMessageTest.class));
+ }
+}
diff --git a/Final/java/client/src/test/java/org/apache/qpid/test/unit/basic/FieldTableKeyEnumeratorTest.java b/Final/java/client/src/test/java/org/apache/qpid/test/unit/basic/FieldTableKeyEnumeratorTest.java
new file mode 100644
index 0000000000..ddbc69826d
--- /dev/null
+++ b/Final/java/client/src/test/java/org/apache/qpid/test/unit/basic/FieldTableKeyEnumeratorTest.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.test.unit.basic;
+
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+import javax.jms.JMSException;
+
+import junit.framework.TestCase;
+
+import org.apache.qpid.client.message.JMSTextMessage;
+import org.apache.qpid.client.message.TestMessageHelper;
+import org.apache.qpid.framing.FieldTable;
+import org.apache.qpid.framing.FieldTableFactory;
+
+public class FieldTableKeyEnumeratorTest extends TestCase
+{
+ public void testTrue()
+ {
+
+ }
+ public void testKeyEnumeration()
+ {
+ FieldTable result = FieldTableFactory.newFieldTable();
+ result.setObject("one", 1L);
+ result.setObject("two", 2L);
+ result.setObject("three", 3L);
+ result.setObject("four", 4L);
+ result.setObject("five", 5L);
+
+ Iterator iterator = result.keys().iterator();
+
+ try
+ {
+ assertTrue("one".equals(iterator.next()));
+ assertTrue("two".equals(iterator.next()));
+ assertTrue("three".equals(iterator.next()));
+ assertTrue("four".equals(iterator.next()));
+ assertTrue("five".equals(iterator.next()));
+ }
+ catch (NoSuchElementException e)
+ {
+ fail("All elements should be found.");
+ }
+
+ }
+
+ public void testPropertEnu()
+ {
+ try
+ {
+ JMSTextMessage text = TestMessageHelper.newJMSTextMessage();
+
+ text.setBooleanProperty("Boolean1", true);
+ text.setBooleanProperty("Boolean2", true);
+ text.setIntProperty("Int", 2);
+ text.setLongProperty("Long", 2);
+
+ Enumeration e = text.getPropertyNames();
+
+ assertTrue("Boolean1".equals(e.nextElement()));
+ assertTrue("Boolean2".equals(e.nextElement()));
+ assertTrue("Int".equals(e.nextElement()));
+ assertTrue("Long".equals(e.nextElement()));
+ }
+ catch (JMSException e)
+ {
+
+ }
+ }
+
+ public static junit.framework.Test suite()
+ {
+ return new junit.framework.TestSuite(FieldTableKeyEnumeratorTest.class);
+ }
+}
diff --git a/Final/java/client/src/test/java/org/apache/qpid/test/unit/basic/FieldTableMessageTest.java b/Final/java/client/src/test/java/org/apache/qpid/test/unit/basic/FieldTableMessageTest.java
new file mode 100644
index 0000000000..aff496becf
--- /dev/null
+++ b/Final/java/client/src/test/java/org/apache/qpid/test/unit/basic/FieldTableMessageTest.java
@@ -0,0 +1,176 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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 junit.framework.TestCase;
+
+import org.apache.mina.common.ByteBuffer;
+
+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.message.JMSBytesMessage;
+import org.apache.qpid.framing.AMQFrameDecodingException;
+import org.apache.qpid.framing.FieldTable;
+import org.apache.qpid.framing.FieldTableFactory;
+import org.apache.qpid.testutil.VMBrokerSetup;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.jms.BytesMessage;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageListener;
+import javax.jms.MessageProducer;
+
+import java.io.IOException;
+import java.util.ArrayList;
+
+public class FieldTableMessageTest extends TestCase implements MessageListener
+{
+ private static final Logger _logger = LoggerFactory.getLogger(FieldTableMessageTest.class);
+
+ private AMQConnection _connection;
+ private AMQDestination _destination;
+ private AMQSession _session;
+ private final ArrayList<JMSBytesMessage> received = new ArrayList<JMSBytesMessage>();
+ private FieldTable _expected;
+ private int _count = 10;
+ public String _connectionString = "vm://:1";
+
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+ init(new AMQConnection(_connectionString, "guest", "guest", randomize("Client"), "test"));
+ }
+
+ protected void tearDown() throws Exception
+ {
+ super.tearDown();
+ }
+
+ private void init(AMQConnection connection) throws Exception
+ {
+ init(connection, new AMQQueue(connection, randomize("FieldTableMessageTest"), true));
+ }
+
+ private void init(AMQConnection connection, AMQDestination destination) throws Exception
+ {
+ _connection = connection;
+ _destination = destination;
+ _session = (AMQSession) connection.createSession(false, AMQSession.NO_ACKNOWLEDGE);
+
+ // set up a slow consumer
+ _session.createConsumer(destination).setMessageListener(this);
+ connection.start();
+
+ // _expected = new FieldTableTest().load("FieldTableTest2.properties");
+ _expected = load();
+ }
+
+ private FieldTable load() throws IOException
+ {
+ FieldTable result = FieldTableFactory.newFieldTable();
+ result.setLong("one", 1L);
+ result.setLong("two", 2L);
+ result.setLong("three", 3L);
+ result.setLong("four", 4L);
+ result.setLong("five", 5L);
+
+ return result;
+ }
+
+ public void test() throws Exception
+ {
+ int count = _count;
+ send(count);
+ waitFor(count);
+ check();
+ _logger.info("Completed without failure");
+ _connection.close();
+ }
+
+ void send(int count) throws JMSException, IOException
+ {
+ // create a publisher
+ MessageProducer producer = _session.createProducer(_destination);
+ for (int i = 0; i < count; i++)
+ {
+ BytesMessage msg = _session.createBytesMessage();
+ msg.writeBytes(_expected.getDataAsBytes());
+ producer.send(msg);
+ }
+ }
+
+ void waitFor(int count) throws InterruptedException
+ {
+ synchronized (received)
+ {
+ while (received.size() < count)
+ {
+ received.wait();
+ }
+ }
+ }
+
+ void check() throws JMSException, AMQFrameDecodingException
+ {
+ for (Object m : received)
+ {
+ ByteBuffer buffer = ((JMSBytesMessage) m).getData();
+ FieldTable actual = FieldTableFactory.newFieldTable(buffer, buffer.remaining());
+ for (String key : _expected.keys())
+ {
+ assertEquals("Values for " + key + " did not match", _expected.getObject(key), actual.getObject(key));
+ }
+ }
+ }
+
+ public void onMessage(Message message)
+ {
+ synchronized (received)
+ {
+ received.add((JMSBytesMessage) message);
+ received.notify();
+ }
+ }
+
+ private static String randomize(String in)
+ {
+ return in + System.currentTimeMillis();
+ }
+
+ public static void main(String[] argv) throws Exception
+ {
+ FieldTableMessageTest test = new FieldTableMessageTest();
+ test._connectionString = (argv.length == 0) ? "vm://:1" : argv[0];
+ test.setUp();
+ test._count = (argv.length > 1) ? Integer.parseInt(argv[1]) : 5;
+ test.test();
+ }
+
+ public static junit.framework.Test suite()
+ {
+ return new VMBrokerSetup(new junit.framework.TestSuite(FieldTableMessageTest.class));
+ }
+}
diff --git a/Final/java/client/src/test/java/org/apache/qpid/test/unit/basic/FieldTablePropertyTest.java b/Final/java/client/src/test/java/org/apache/qpid/test/unit/basic/FieldTablePropertyTest.java
new file mode 100644
index 0000000000..60ed688897
--- /dev/null
+++ b/Final/java/client/src/test/java/org/apache/qpid/test/unit/basic/FieldTablePropertyTest.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.test.unit.basic;
+
+import java.util.Enumeration;
+
+import javax.jms.JMSException;
+
+import junit.framework.TestCase;
+
+import org.apache.qpid.client.message.JMSTextMessage;
+import org.apache.qpid.client.message.TestMessageHelper;
+
+public class FieldTablePropertyTest extends TestCase
+{
+ public void testPropertyNames()
+ {
+ try
+ {
+ JMSTextMessage text = TestMessageHelper.newJMSTextMessage();
+
+ text.setBooleanProperty("Boolean1", true);
+ text.setBooleanProperty("Boolean2", true);
+ text.setIntProperty("Int", 2);
+ text.setLongProperty("Long", 2);
+
+ Enumeration e = text.getPropertyNames();
+
+ assertEquals("Boolean1", e.nextElement());
+ assertTrue("Boolean2".equals(e.nextElement()));
+ assertTrue("Int".equals(e.nextElement()));
+ assertTrue("Long".equals(e.nextElement()));
+ }
+ catch (JMSException e)
+ {
+
+ }
+ }
+
+ public static junit.framework.Test suite()
+ {
+ return new junit.framework.TestSuite(FieldTablePropertyTest.class);
+ }
+}
diff --git a/Final/java/client/src/test/java/org/apache/qpid/test/unit/basic/InvalidDestinationTest.java b/Final/java/client/src/test/java/org/apache/qpid/test/unit/basic/InvalidDestinationTest.java
new file mode 100644
index 0000000000..83846e0081
--- /dev/null
+++ b/Final/java/client/src/test/java/org/apache/qpid/test/unit/basic/InvalidDestinationTest.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.test.unit.basic;
+
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.client.AMQDestination;
+import org.apache.qpid.client.AMQSession;
+import org.apache.qpid.client.AMQQueue;
+import org.apache.qpid.client.vmbroker.AMQVMBrokerCreationException;
+import org.apache.qpid.client.transport.TransportConnection;
+
+import junit.framework.TestCase;
+
+import javax.jms.MessageConsumer;
+import javax.jms.Session;
+import javax.jms.QueueSession;
+import javax.jms.Queue;
+import javax.jms.QueueSender;
+import javax.jms.TextMessage;
+import javax.jms.InvalidDestinationException;
+
+public class InvalidDestinationTest extends TestCase
+{
+ private AMQConnection _connection;
+ private AMQDestination _destination;
+ private AMQSession _session;
+ private MessageConsumer _consumer;
+
+ private static final String VM_BROKER = "vm://:1";
+
+
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+ createVMBroker();
+ _connection = new AMQConnection(VM_BROKER, "guest", "guest", "ReceiveTestClient", "test");
+ }
+
+ public void createVMBroker()
+ {
+ try
+ {
+ TransportConnection.createVMBroker(1);
+ }
+ catch (AMQVMBrokerCreationException e)
+ {
+ fail("Unable to create broker: " + e);
+ }
+ }
+
+ protected void tearDown() throws Exception
+ {
+ _connection.close();
+ TransportConnection.killVMBroker(1);
+ super.tearDown();
+ }
+
+
+
+ public void testInvalidDestination() throws Exception
+ {
+ Queue invalidDestination = new AMQQueue("amq.direct","unknownQ");
+ AMQQueue validDestination = new AMQQueue("amq.direct","knownQ");
+ QueueSession queueSession = _connection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ // This is the only easy way to create and bind a queue from the API :-(
+ MessageConsumer consumer = queueSession.createConsumer(validDestination);
+
+ QueueSender sender = queueSession.createSender(invalidDestination);
+ TextMessage msg = queueSession.createTextMessage("Hello");
+ try
+ {
+ sender.send(msg);
+ fail("Expected InvalidDestinationException");
+ }
+ catch (InvalidDestinationException ex)
+ {
+ // pass
+ }
+ sender.close();
+
+ sender = queueSession.createSender(null);
+ invalidDestination = new AMQQueue("amq.direct","unknownQ");
+
+ try
+ {
+ sender.send(invalidDestination,msg);
+ fail("Expected InvalidDestinationException");
+ }
+ catch (InvalidDestinationException ex)
+ {
+ // pass
+ }
+ sender.send(validDestination,msg);
+ sender.close();
+ validDestination = new AMQQueue("amq.direct","knownQ");
+ sender = queueSession.createSender(validDestination);
+ sender.send(msg);
+
+
+
+
+ }
+
+
+ public static junit.framework.Test suite()
+ {
+
+ return new junit.framework.TestSuite(InvalidDestinationTest.class);
+ }
+}
diff --git a/Final/java/client/src/test/java/org/apache/qpid/test/unit/basic/LargeMessageTest.java b/Final/java/client/src/test/java/org/apache/qpid/test/unit/basic/LargeMessageTest.java
new file mode 100644
index 0000000000..03698b2ab2
--- /dev/null
+++ b/Final/java/client/src/test/java/org/apache/qpid/test/unit/basic/LargeMessageTest.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.unit.basic;
+
+import junit.framework.TestCase;
+
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.client.AMQQueue;
+import org.apache.qpid.client.AMQSession;
+import org.apache.qpid.client.message.JMSTextMessage;
+import org.apache.qpid.client.transport.TransportConnection;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.jms.Destination;
+import javax.jms.JMSException;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageProducer;
+import javax.jms.Session;
+import javax.jms.TextMessage;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class LargeMessageTest extends TestCase
+{
+ private static final Logger _logger = LoggerFactory.getLogger(LargeMessageTest.class);
+
+ private AMQConnection _connection;
+ private Destination _destination;
+ private AMQSession _session;
+ private final List<JMSTextMessage> received = new ArrayList<JMSTextMessage>();
+ public String _broker = "vm://:1";
+
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+ TransportConnection.createVMBroker(1);
+ try
+ {
+ init(new AMQConnection(_broker, "guest", "guest", "LargeMessageTest", "test"));
+ }
+ catch (Exception e)
+ {
+ fail("Unable to initialilse connection: " + e);
+ }
+ }
+
+ protected void tearDown() throws Exception
+ {
+ super.tearDown();
+ _session.close();
+ _connection.close();
+ TransportConnection.killAllVMBrokers();
+ }
+
+ private void init(AMQConnection connection) throws Exception
+ {
+ Destination destination = new AMQQueue(connection, "LargeMessageTest", true);
+ init(connection, destination);
+ }
+
+ private void init(AMQConnection connection, Destination destination) throws Exception
+ {
+ _connection = connection;
+ _destination = destination;
+ _session = (AMQSession) connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ connection.start();
+ }
+
+ // Test boundary of 1 packet to 2 packets
+ public void test64kminus1()
+ {
+ checkLargeMessage((64 * 1024) - 1);
+ }
+
+ public void test64k()
+ {
+ checkLargeMessage(64 * 1024);
+ }
+
+ public void test64kplus1()
+ {
+ checkLargeMessage((64 * 1024) + 1);
+ }
+
+ // Test packet boundary of 3 packtes
+ public void test128kminus1()
+ {
+ checkLargeMessage((128 * 1024) - 1);
+ }
+
+ public void test128k()
+ {
+ checkLargeMessage(128 * 1024);
+ }
+
+ public void test128kplus1()
+ {
+ checkLargeMessage((128 * 1024) + 1);
+ }
+
+ // Testing larger messages
+
+ public void test256k()
+ {
+ checkLargeMessage(256 * 1024);
+ }
+
+ public void test512k()
+ {
+ checkLargeMessage(512 * 1024);
+ }
+
+ public void test1024k()
+ {
+ checkLargeMessage(1024 * 1024);
+ }
+
+ protected void checkLargeMessage(int messageSize)
+ {
+ try
+ {
+ MessageConsumer consumer = _session.createConsumer(_destination);
+ MessageProducer producer = _session.createProducer(_destination);
+ _logger.info("Testing message of size:" + messageSize);
+
+ String _messageText = buildLargeMessage(messageSize);
+
+ _logger.debug("Message built");
+
+ producer.send(_session.createTextMessage(_messageText));
+
+ TextMessage result = (TextMessage) consumer.receive(10000);
+
+ assertNotNull("Null message recevied", result);
+ assertEquals("Message Size", _messageText.length(), result.getText().length());
+ assertEquals("Message content differes", _messageText, result.getText());
+ }
+ catch (JMSException e)
+ {
+ e.printStackTrace();
+ fail("Excpetion occured:" + e.getCause());
+ }
+ }
+
+ private String buildLargeMessage(int size)
+ {
+ StringBuilder builder = new StringBuilder(size);
+
+ char ch = 'a';
+
+ for (int i = 1; i <= size; i++)
+ {
+ builder.append(ch);
+
+ if ((i % 1000) == 0)
+ {
+ ch++;
+ if (ch == ('z' + 1))
+ {
+ ch = 'a';
+ }
+ }
+ }
+
+ return builder.toString();
+ }
+
+ public static junit.framework.Test suite()
+ {
+ return new junit.framework.TestSuite(LargeMessageTest.class);
+ }
+}
diff --git a/Final/java/client/src/test/java/org/apache/qpid/test/unit/basic/MapMessageTest.java b/Final/java/client/src/test/java/org/apache/qpid/test/unit/basic/MapMessageTest.java
new file mode 100644
index 0000000000..6708fefa86
--- /dev/null
+++ b/Final/java/client/src/test/java/org/apache/qpid/test/unit/basic/MapMessageTest.java
@@ -0,0 +1,1277 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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 junit.framework.Assert;
+import junit.framework.TestCase;
+
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.client.AMQQueue;
+import org.apache.qpid.client.AMQSession;
+import org.apache.qpid.client.message.JMSMapMessage;
+import org.apache.qpid.client.transport.TransportConnection;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.jms.Destination;
+import javax.jms.JMSException;
+import javax.jms.MapMessage;
+import javax.jms.Message;
+import javax.jms.MessageFormatException;
+import javax.jms.MessageListener;
+import javax.jms.MessageNotWriteableException;
+import javax.jms.MessageProducer;
+import javax.jms.Session;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+public class MapMessageTest extends TestCase implements MessageListener
+{
+ private static final Logger _logger = LoggerFactory.getLogger(MapMessageTest.class);
+
+ private AMQConnection _connection;
+ private Destination _destination;
+ private AMQSession _session;
+ private final List<JMSMapMessage> received = new ArrayList<JMSMapMessage>();
+
+ private static final String MESSAGE = "Message ";
+ private int _count = 100;
+ public String _connectionString = "vm://:1";
+ private byte[] _bytes = { 99, 98, 97, 96, 95 };
+ private static final float _smallfloat = 100.0f;
+
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+ try
+ {
+ TransportConnection.createVMBroker(1);
+ init(new AMQConnection(_connectionString, "guest", "guest", randomize("Client"), "test"));
+ }
+ catch (Exception e)
+ {
+ fail("Unable to initialilse connection: " + e);
+ }
+ }
+
+ protected void tearDown() throws Exception
+ {
+ _logger.info("Tearing Down unit.basic.MapMessageTest");
+ super.tearDown();
+ TransportConnection.killAllVMBrokers();
+ }
+
+ private void init(AMQConnection connection) throws Exception
+ {
+ Destination destination = new AMQQueue(connection, randomize("MapMessageTest"), true);
+ init(connection, destination);
+ }
+
+ private void init(AMQConnection connection, Destination destination) throws Exception
+ {
+ _connection = connection;
+ _destination = destination;
+ _session = (AMQSession) connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ // set up a slow consumer
+ _session.createConsumer(destination).setMessageListener(this);
+ connection.start();
+ }
+
+ public void test() throws Exception
+ {
+ int count = _count;
+ send(count);
+ waitFor(count);
+ check();
+ _connection.close();
+ }
+
+ void send(int count) throws JMSException
+ {
+ // create a publisher
+ MessageProducer producer = _session.createProducer(_destination);
+ for (int i = 0; i < count; i++)
+ {
+ MapMessage message = _session.createMapMessage();
+
+ setMapValues(message, i);
+
+ producer.send(message);
+ }
+ }
+
+ private void setMapValues(MapMessage message, int i) throws JMSException
+ {
+ message.setBoolean("odd", (i / 2) == 0);
+ message.setByte("byte", (byte) Byte.MAX_VALUE);
+ message.setBytes("bytes", _bytes);
+ message.setChar("char", (char) 'c');
+ message.setDouble("double", (double) Double.MAX_VALUE);
+ message.setFloat("float", (float) Float.MAX_VALUE);
+ message.setFloat("smallfloat", 100);
+ message.setInt("messageNumber", i);
+ message.setInt("int", (int) Integer.MAX_VALUE);
+ message.setLong("long", (long) Long.MAX_VALUE);
+ message.setShort("short", (short) Short.MAX_VALUE);
+ message.setString("message", MESSAGE + i);
+
+ // Test Setting Object Values
+ message.setObject("object-bool", true);
+ message.setObject("object-byte", Byte.MAX_VALUE);
+ message.setObject("object-bytes", _bytes);
+ message.setObject("object-char", 'c');
+ message.setObject("object-double", Double.MAX_VALUE);
+ message.setObject("object-float", Float.MAX_VALUE);
+ message.setObject("object-int", Integer.MAX_VALUE);
+ message.setObject("object-long", Long.MAX_VALUE);
+ message.setObject("object-short", Short.MAX_VALUE);
+
+ // Set a null String value
+ message.setString("nullString", null);
+ // Highlight protocol problem
+ message.setString("emptyString", "");
+
+ }
+
+ void waitFor(int count) throws Exception
+ {
+ long waitTime = 30000L;
+ long waitUntilTime = System.currentTimeMillis() + 30000L;
+
+ synchronized (received)
+ {
+ while ((received.size() < count) && (waitTime > 0))
+ {
+ if (received.size() < count)
+ {
+ received.wait(waitTime);
+ }
+
+ if (received.size() < count)
+ {
+ waitTime = waitUntilTime - System.currentTimeMillis();
+ }
+ }
+
+ if (received.size() < count)
+ {
+ throw new Exception("Timed-out. Waiting for " + count + " only got " + received.size());
+ }
+ }
+ }
+
+ void check() throws JMSException
+ {
+ List<String> actual = new ArrayList<String>();
+ int count = 0;
+ for (JMSMapMessage m : received)
+ {
+ actual.add(m.getString("message"));
+
+ testMapValues(m, count);
+
+ testCorrectExceptions(m);
+
+ testMessageWriteStatus(m);
+
+ testPropertyWriteStatus(m);
+
+ count++;
+ }
+ }
+
+ private void testCorrectExceptions(JMSMapMessage m) throws JMSException
+ {
+ testBoolean(m);
+
+ testByte(m);
+
+ testBytes(m);
+
+ testChar(m);
+
+ testDouble(m);
+
+ testFloat(m);
+
+ testInt(m);
+
+ testLong(m);
+
+ testShort(m);
+
+ testString(m);
+ }
+
+ private void testString(JMSMapMessage m) throws JMSException
+ {
+
+ Assert.assertFalse(m.getBoolean("message"));
+
+ try
+ {
+ m.getByte("message");
+ fail("Exception Expected.");
+ }
+ catch (NumberFormatException nfe)
+ {
+ // normal execution
+ }
+
+ try
+ {
+ m.getShort("message");
+ fail("Exception Expected.");
+ }
+ catch (NumberFormatException nfe)
+ {
+ // normal execution
+ }
+
+ // Try bad reads
+ try
+ {
+ m.getChar("message");
+ fail("Exception Expected.");
+ }
+ catch (MessageFormatException npe)
+ {
+ // normal execution
+ }
+
+ try
+ {
+ m.getInt("message");
+ fail("Exception Expected.");
+ }
+ catch (NumberFormatException nfe)
+ {
+ // normal execution
+ }
+
+ try
+ {
+ m.getLong("message");
+ fail("Exception Expected.");
+ }
+ catch (NumberFormatException nfe)
+ {
+ // normal execution
+ }
+
+ // Try bad reads
+ try
+ {
+ m.getFloat("message");
+ fail("Exception Expected.");
+ }
+ catch (NumberFormatException nfe)
+ {
+ // normal execution
+ }
+ // Try bad reads
+ try
+ {
+ m.getDouble("message");
+ fail("Exception Expected.");
+ }
+ catch (NumberFormatException nfe)
+ {
+ // normal execution
+ }
+ // Try bad reads
+ try
+ {
+ m.getBytes("message");
+ fail("Exception Expected.");
+ }
+ catch (MessageFormatException nfe)
+ {
+ // normal execution
+ }
+
+ Assert.assertEquals(MESSAGE + m.getInt("messageNumber"), m.getString("message"));
+ }
+
+ private void testShort(JMSMapMessage m) throws JMSException
+ {
+
+ // Try bad reads
+ try
+ {
+ m.getBoolean("short");
+ fail("Exception Expected.");
+ }
+ catch (MessageFormatException nfe)
+ {
+ // normal execution
+ }
+
+ try
+ {
+ m.getByte("short");
+ fail("Exception Expected.");
+ }
+ catch (MessageFormatException nfe)
+ {
+ // normal execution
+ }
+
+ Assert.assertEquals(Short.MAX_VALUE, m.getShort("short"));
+
+ // Try bad reads
+ try
+ {
+ m.getChar("short");
+ fail("Exception Expected.");
+ }
+ catch (MessageFormatException npe)
+ {
+ // normal execution
+ }
+
+ Assert.assertEquals(Short.MAX_VALUE, m.getInt("short"));
+
+ Assert.assertEquals(Short.MAX_VALUE, m.getLong("short"));
+
+ // Try bad reads
+ try
+ {
+ m.getFloat("short");
+ fail("Exception Expected.");
+ }
+ catch (MessageFormatException nfe)
+ {
+ // normal execution
+ }
+ // Try bad reads
+ try
+ {
+ m.getDouble("short");
+ fail("Exception Expected.");
+ }
+ catch (MessageFormatException nfe)
+ {
+ // normal execution
+ }
+ // Try bad reads
+ try
+ {
+ m.getBytes("short");
+ fail("Exception Expected.");
+ }
+ catch (MessageFormatException nfe)
+ {
+ // normal execution
+ }
+
+ Assert.assertEquals("" + Short.MAX_VALUE, m.getString("short"));
+ }
+
+ private void testLong(JMSMapMessage m) throws JMSException
+ {
+
+ // Try bad reads
+ try
+ {
+ m.getBoolean("long");
+ fail("Exception Expected.");
+ }
+ catch (MessageFormatException nfe)
+ {
+ // normal execution
+ }
+
+ try
+ {
+ m.getByte("long");
+ fail("Exception Expected.");
+ }
+ catch (MessageFormatException nfe)
+ {
+ // normal execution
+ }
+
+ try
+ {
+ m.getShort("long");
+ fail("Exception Expected.");
+ }
+ catch (MessageFormatException nfe)
+ {
+ // normal execution
+ }
+
+ // Try bad reads
+ try
+ {
+ m.getChar("long");
+ fail("Exception Expected.");
+ }
+ catch (MessageFormatException npe)
+ {
+ // normal execution
+ }
+
+ try
+ {
+ m.getInt("long");
+ fail("Exception Expected.");
+ }
+ catch (MessageFormatException nfe)
+ {
+ // normal execution
+ }
+
+ Assert.assertEquals(Long.MAX_VALUE, m.getLong("long"));
+
+ // Try bad reads
+ try
+ {
+ m.getFloat("long");
+ fail("Exception Expected.");
+ }
+ catch (MessageFormatException nfe)
+ {
+ // normal execution
+ }
+ // Try bad reads
+ try
+ {
+ m.getDouble("long");
+ fail("Exception Expected.");
+ }
+ catch (MessageFormatException nfe)
+ {
+ // normal execution
+ }
+ // Try bad reads
+ try
+ {
+ m.getBytes("long");
+ fail("Exception Expected.");
+ }
+ catch (MessageFormatException nfe)
+ {
+ // normal execution
+ }
+
+ Assert.assertEquals("" + Long.MAX_VALUE, m.getString("long"));
+ }
+
+ private void testDouble(JMSMapMessage m) throws JMSException
+ {
+
+ // Try bad reads
+ try
+ {
+ m.getBoolean("double");
+ fail("Exception Expected.");
+ }
+ catch (MessageFormatException nfe)
+ {
+ // normal execution
+ }
+
+ try
+ {
+ m.getByte("double");
+ fail("Exception Expected.");
+ }
+ catch (MessageFormatException nfe)
+ {
+ // normal execution
+ }
+
+ try
+ {
+ m.getShort("double");
+ fail("Exception Expected.");
+ }
+ catch (MessageFormatException nfe)
+ {
+ // normal execution
+ }
+
+ // Try bad reads
+ try
+ {
+ m.getChar("double");
+ fail("Exception Expected.");
+ }
+ catch (MessageFormatException npe)
+ {
+ // normal execution
+ }
+
+ try
+ {
+ m.getInt("double");
+ fail("Exception Expected.");
+ }
+ catch (MessageFormatException nfe)
+ {
+ // normal execution
+ }
+
+ try
+ {
+ m.getLong("double");
+ fail("Exception Expected.");
+ }
+ catch (MessageFormatException nfe)
+ {
+ // normal execution
+ }
+
+ // Try bad reads
+ try
+ {
+ m.getFloat("double");
+ fail("Exception Expected.");
+ }
+ catch (MessageFormatException nfe)
+ {
+ // normal execution
+ }
+
+ Assert.assertEquals(Double.MAX_VALUE, m.getDouble("double"));
+
+ // Try bad reads
+ try
+ {
+ m.getBytes("double");
+ fail("Exception Expected.");
+ }
+ catch (MessageFormatException nfe)
+ {
+ // normal execution
+ }
+
+ Assert.assertEquals("" + Double.MAX_VALUE, m.getString("double"));
+ }
+
+ private void testFloat(JMSMapMessage m) throws JMSException
+ {
+
+ // Try bad reads
+ try
+ {
+ m.getBoolean("float");
+ fail("Exception Expected.");
+ }
+ catch (MessageFormatException nfe)
+ {
+ // normal execution
+ }
+
+ try
+ {
+ m.getByte("float");
+ fail("Exception Expected.");
+ }
+ catch (MessageFormatException nfe)
+ {
+ // normal execution
+ }
+
+ try
+ {
+ m.getShort("float");
+ fail("Exception Expected.");
+ }
+ catch (MessageFormatException nfe)
+ {
+ // normal execution
+ }
+
+ // Try bad reads
+ try
+ {
+ m.getChar("float");
+ fail("Exception Expected.");
+ }
+ catch (MessageFormatException npe)
+ {
+ // normal execution
+ }
+
+ try
+ {
+ m.getInt("float");
+ fail("Exception Expected.");
+ }
+ catch (MessageFormatException nfe)
+ {
+ // normal execution
+ }
+
+ try
+ {
+ m.getLong("float");
+ fail("Exception Expected.");
+ }
+ catch (MessageFormatException nfe)
+ {
+ // normal execution
+ }
+
+ Assert.assertEquals(Float.MAX_VALUE, m.getFloat("float"));
+
+ Assert.assertEquals(_smallfloat, (float) m.getDouble("smallfloat"));
+
+ // Try bad reads
+ try
+ {
+ m.getBytes("float");
+ fail("Exception Expected.");
+ }
+ catch (MessageFormatException nfe)
+ {
+ // normal execution
+ }
+
+ Assert.assertEquals("" + Float.MAX_VALUE, m.getString("float"));
+ }
+
+ private void testInt(JMSMapMessage m) throws JMSException
+ {
+
+ // Try bad reads
+ try
+ {
+ m.getBoolean("int");
+ fail("Exception Expected.");
+ }
+ catch (MessageFormatException nfe)
+ {
+ // normal execution
+ }
+
+ try
+ {
+ m.getByte("int");
+ fail("Exception Expected.");
+ }
+ catch (MessageFormatException nfe)
+ {
+ // normal execution
+ }
+
+ try
+ {
+ m.getShort("int");
+ fail("Exception Expected.");
+ }
+ catch (MessageFormatException nfe)
+ {
+ // normal execution
+ }
+
+ // Try bad reads
+ try
+ {
+ m.getChar("int");
+ fail("Exception Expected.");
+ }
+ catch (MessageFormatException npe)
+ {
+ // normal execution
+ }
+
+ Assert.assertEquals(Integer.MAX_VALUE, m.getInt("int"));
+
+ Assert.assertEquals(Integer.MAX_VALUE, (int) m.getLong("int"));
+
+ // Try bad reads
+ try
+ {
+ m.getFloat("int");
+ fail("Exception Expected.");
+ }
+ catch (MessageFormatException nfe)
+ {
+ // normal execution
+ }
+ // Try bad reads
+ try
+ {
+ m.getDouble("int");
+ fail("Exception Expected.");
+ }
+ catch (MessageFormatException nfe)
+ {
+ // normal execution
+ }
+ // Try bad reads
+ try
+ {
+ m.getBytes("int");
+ fail("Exception Expected.");
+ }
+ catch (MessageFormatException nfe)
+ {
+ // normal execution
+ }
+
+ Assert.assertEquals("" + Integer.MAX_VALUE, m.getString("int"));
+ }
+
+ private void testChar(JMSMapMessage m) throws JMSException
+ {
+
+ // Try bad reads
+ try
+ {
+ m.getBoolean("char");
+ fail("Exception Expected.");
+ }
+ catch (MessageFormatException nfe)
+ {
+ // normal execution
+ }
+
+ try
+ {
+ m.getByte("char");
+ fail("Exception Expected.");
+ }
+ catch (MessageFormatException nfe)
+ {
+ // normal execution
+ }
+
+ try
+ {
+ m.getShort("char");
+ fail("Exception Expected.");
+ }
+ catch (MessageFormatException nfe)
+ {
+ // normal execution
+ }
+
+ Assert.assertEquals('c', m.getChar("char"));
+
+ try
+ {
+ m.getInt("char");
+ fail("Exception Expected.");
+ }
+ catch (MessageFormatException nfe)
+ {
+ // normal execution
+ }
+
+ try
+ {
+ m.getLong("char");
+ fail("Exception Expected.");
+ }
+ catch (MessageFormatException nfe)
+ {
+ // normal execution
+ }
+
+ // Try bad reads
+ try
+ {
+ m.getFloat("char");
+ fail("Exception Expected.");
+ }
+ catch (MessageFormatException nfe)
+ {
+ // normal execution
+ }
+ // Try bad reads
+ try
+ {
+ m.getDouble("char");
+ fail("Exception Expected.");
+ }
+ catch (MessageFormatException nfe)
+ {
+ // normal execution
+ }
+ // Try bad reads
+ try
+ {
+ m.getBytes("char");
+ fail("Exception Expected.");
+ }
+ catch (MessageFormatException nfe)
+ {
+ // normal execution
+ }
+
+ Assert.assertEquals("" + 'c', m.getString("char"));
+ }
+
+ private void testBytes(JMSMapMessage m) throws JMSException
+ {
+ // Try bad reads
+ try
+ {
+ m.getBoolean("bytes");
+ fail("Exception Expected.");
+ }
+ catch (MessageFormatException nfe)
+ {
+ // normal execution
+ }
+
+ try
+ {
+ m.getByte("bytes");
+ fail("Exception Expected.");
+ }
+ catch (MessageFormatException nfe)
+ {
+ // normal execution
+ }
+
+ try
+ {
+ m.getShort("bytes");
+ fail("Exception Expected.");
+ }
+ catch (MessageFormatException nfe)
+ {
+ // normal execution
+ }
+
+ // Try bad reads
+ try
+ {
+ m.getChar("bytes");
+ fail("Exception Expected.");
+ }
+ catch (MessageFormatException npe)
+ {
+ // normal execution
+ }
+
+ try
+ {
+ m.getInt("bytes");
+ fail("Exception Expected.");
+ }
+ catch (MessageFormatException nfe)
+ {
+ // normal execution
+ }
+
+ try
+ {
+ m.getLong("bytes");
+ fail("Exception Expected.");
+ }
+ catch (MessageFormatException nfe)
+ {
+ // normal execution
+ }
+
+ // Try bad reads
+ try
+ {
+ m.getFloat("bytes");
+ fail("Exception Expected.");
+ }
+ catch (MessageFormatException nfe)
+ {
+ // normal execution
+ }
+ // Try bad reads
+ try
+ {
+ m.getDouble("bytes");
+ fail("Exception Expected.");
+ }
+ catch (MessageFormatException nfe)
+ {
+ // normal execution
+ }
+
+ assertBytesEqual(_bytes, m.getBytes("bytes"));
+
+ try
+ {
+ m.getString("bytes");
+ fail("Exception Expected.");
+ }
+ catch (MessageFormatException nfe)
+ {
+ // normal execution
+ }
+
+ }
+
+ private void testByte(JMSMapMessage m) throws JMSException
+ {
+ // Try bad reads
+ try
+ {
+ m.getBoolean("byte");
+ fail("Exception Expected.");
+ }
+ catch (MessageFormatException nfe)
+ {
+ // normal execution
+ }
+
+ Assert.assertEquals(Byte.MAX_VALUE, m.getByte("byte"));
+
+ Assert.assertEquals((short) Byte.MAX_VALUE, m.getShort("byte"));
+
+ // Try bad reads
+ try
+ {
+ m.getChar("byte");
+ fail("Exception Expected.");
+ }
+ catch (MessageFormatException npe)
+ {
+ // normal execution
+ }
+
+ // Reading a byte as an int is ok
+ Assert.assertEquals((short) Byte.MAX_VALUE, m.getInt("byte"));
+
+ Assert.assertEquals((short) Byte.MAX_VALUE, m.getLong("byte"));
+
+ // Try bad reads
+ try
+ {
+ m.getFloat("byte");
+ fail("Exception Expected.");
+ }
+ catch (MessageFormatException nfe)
+ {
+ // normal execution
+ }
+ // Try bad reads
+ try
+ {
+ m.getDouble("byte");
+ fail("Exception Expected.");
+ }
+ catch (MessageFormatException nfe)
+ {
+ // normal execution
+ }
+ // Try bad reads
+ try
+ {
+ m.getBytes("byte");
+ fail("Exception Expected.");
+ }
+ catch (MessageFormatException nfe)
+ {
+ // normal execution
+ }
+
+ Assert.assertEquals("" + Byte.MAX_VALUE, m.getString("byte"));
+
+ }
+
+ private void testBoolean(JMSMapMessage m) throws JMSException
+ {
+
+ Assert.assertEquals((m.getInt("messageNumber") / 2) == 0, m.getBoolean("odd"));
+
+ // Try bad reads
+ try
+ {
+ m.getByte("odd");
+ fail("Exception Expected.");
+ }
+ catch (MessageFormatException nfe)
+ {
+ // normal execution
+ }
+
+ // Try bad reads
+ try
+ {
+ m.getShort("odd");
+ fail("Exception Expected.");
+ }
+ catch (MessageFormatException nfe)
+ {
+ // normal execution
+ }
+ // Try bad reads
+ try
+ {
+ m.getChar("odd");
+ fail("Exception Expected.");
+ }
+ catch (MessageFormatException npe)
+ {
+ // normal execution
+ }
+ // Try bad reads
+ try
+ {
+ m.getInt("odd");
+ fail("Exception Expected.");
+ }
+ catch (MessageFormatException nfe)
+ {
+ // normal execution
+ }
+ // Try bad reads
+ try
+ {
+ m.getLong("odd");
+ fail("Exception Expected.");
+ }
+ catch (MessageFormatException nfe)
+ {
+ // normal execution
+ }
+ // Try bad reads
+ try
+ {
+ m.getFloat("odd");
+ fail("Exception Expected.");
+ }
+ catch (MessageFormatException nfe)
+ {
+ // normal execution
+ }
+ // Try bad reads
+ try
+ {
+ m.getDouble("odd");
+ fail("Exception Expected.");
+ }
+ catch (MessageFormatException nfe)
+ {
+ // normal execution
+ }
+ // Try bad reads
+ try
+ {
+ m.getBytes("odd");
+ fail("Exception Expected.");
+ }
+ catch (MessageFormatException nfe)
+ {
+ // normal execution
+ }
+
+ Assert.assertEquals("" + ((m.getInt("messageNumber") / 2) == 0), m.getString("odd"));
+ }
+
+ private void testPropertyWriteStatus(JMSMapMessage m) throws JMSException
+ {
+ // Check property write status
+ try
+ {
+ m.setStringProperty("test", "test");
+ Assert.fail("Message should not be writeable");
+ }
+ catch (MessageNotWriteableException mnwe)
+ {
+ // normal execution
+ }
+
+ m.clearProperties();
+
+ try
+ {
+ m.setStringProperty("test", "test");
+ }
+ catch (MessageNotWriteableException mnwe)
+ {
+ Assert.fail("Message should be writeable");
+ }
+ }
+
+ private void testMessageWriteStatus(JMSMapMessage m) throws JMSException
+ {
+ try
+ {
+ m.setInt("testint", 3);
+ fail("Message should not be writeable");
+ }
+ catch (MessageNotWriteableException mnwe)
+ {
+ // normal execution
+ }
+
+ m.clearBody();
+
+ try
+ {
+ m.setInt("testint", 3);
+ }
+ catch (MessageNotWriteableException mnwe)
+ {
+ Assert.fail("Message should be writeable");
+ }
+ }
+
+ private void testMapValues(JMSMapMessage m, int count) throws JMSException
+ {
+ // Test get<Primiative>
+
+ // Boolean
+ assertEqual((count / 2) == 0, m.getBoolean("odd"));
+ assertEqual("" + ((count / 2) == 0), m.getString("odd"));
+
+ // Byte
+ assertEqual(Byte.MAX_VALUE, m.getByte("byte"));
+ assertEqual("" + Byte.MAX_VALUE, m.getString("byte"));
+
+ // Bytes
+ assertBytesEqual(_bytes, m.getBytes("bytes"));
+
+ // Char
+ assertEqual('c', m.getChar("char"));
+
+ // Double
+ assertEqual(Double.MAX_VALUE, m.getDouble("double"));
+ assertEqual("" + Double.MAX_VALUE, m.getString("double"));
+
+ // Float
+ assertEqual(Float.MAX_VALUE, m.getFloat("float"));
+ assertEqual(_smallfloat, (float) m.getDouble("smallfloat"));
+ assertEqual("" + Float.MAX_VALUE, m.getString("float"));
+
+ // Integer
+ assertEqual(Integer.MAX_VALUE, m.getInt("int"));
+ assertEqual("" + Integer.MAX_VALUE, m.getString("int"));
+ assertEqual(count, m.getInt("messageNumber"));
+
+ // long
+ assertEqual(Long.MAX_VALUE, m.getLong("long"));
+ assertEqual("" + Long.MAX_VALUE, m.getString("long"));
+
+ // Short
+ assertEqual(Short.MAX_VALUE, m.getShort("short"));
+ assertEqual("" + Short.MAX_VALUE, m.getString("short"));
+ assertEqual((int) Short.MAX_VALUE, m.getInt("short"));
+
+ // String
+ assertEqual(MESSAGE + count, m.getString("message"));
+
+ // Test getObjects
+ assertEqual(true, m.getObject("object-bool"));
+ assertEqual(Byte.MAX_VALUE, m.getObject("object-byte"));
+ assertBytesEqual(_bytes, (byte[]) m.getObject("object-bytes"));
+ assertEqual('c', m.getObject("object-char"));
+ assertEqual(Double.MAX_VALUE, m.getObject("object-double"));
+ assertEqual(Float.MAX_VALUE, m.getObject("object-float"));
+ assertEqual(Integer.MAX_VALUE, m.getObject("object-int"));
+ assertEqual(Long.MAX_VALUE, m.getObject("object-long"));
+ assertEqual(Short.MAX_VALUE, m.getObject("object-short"));
+
+ // Check Special values
+ assertTrue(m.getString("nullString") == null);
+ assertEqual("", m.getString("emptyString"));
+ }
+
+ private void assertBytesEqual(byte[] expected, byte[] actual)
+ {
+ Assert.assertEquals(expected.length, actual.length);
+
+ for (int index = 0; index < expected.length; index++)
+ {
+ Assert.assertEquals(expected[index], actual[index]);
+ }
+ }
+
+ private static void assertEqual(Iterator expected, Iterator actual)
+ {
+ List<String> errors = new ArrayList<String>();
+ while (expected.hasNext() && actual.hasNext())
+ {
+ try
+ {
+ assertEqual(expected.next(), actual.next());
+ }
+ catch (Exception e)
+ {
+ errors.add(e.getMessage());
+ }
+ }
+ while (expected.hasNext())
+ {
+ errors.add("Expected " + expected.next() + " but no more actual values.");
+ }
+ while (actual.hasNext())
+ {
+ errors.add("Found " + actual.next() + " but no more expected values.");
+ }
+
+ if (!errors.isEmpty())
+ {
+ throw new RuntimeException(errors.toString());
+ }
+ }
+
+ private static void assertEqual(Object expected, Object actual)
+ {
+ if (!expected.equals(actual))
+ {
+ throw new RuntimeException("Expected '" + expected + "' found '" + actual + "'");
+ }
+ }
+
+ public void onMessage(Message message)
+ {
+ synchronized (received)
+ {
+ _logger.info("****************** Recevied Messgage:" + (JMSMapMessage) message);
+ received.add((JMSMapMessage) message);
+ received.notify();
+ }
+ }
+
+ private static String randomize(String in)
+ {
+ return in + System.currentTimeMillis();
+ }
+
+ public static void main(String[] argv) throws Exception
+ {
+ MapMessageTest test = new MapMessageTest();
+ test._connectionString = (argv.length == 0) ? "vm://:1" : argv[0];
+ test.setUp();
+ if (argv.length > 1)
+ {
+ test._count = Integer.parseInt(argv[1]);
+ }
+
+ test.test();
+ }
+
+ public static junit.framework.Test suite()
+ {
+ return new junit.framework.TestSuite(MapMessageTest.class);
+ }
+}
diff --git a/Final/java/client/src/test/java/org/apache/qpid/test/unit/basic/MultipleConnectionTest.java b/Final/java/client/src/test/java/org/apache/qpid/test/unit/basic/MultipleConnectionTest.java
new file mode 100644
index 0000000000..65b3d60ad9
--- /dev/null
+++ b/Final/java/client/src/test/java/org/apache/qpid/test/unit/basic/MultipleConnectionTest.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.test.unit.basic;
+
+import junit.framework.TestCase;
+
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.client.AMQDestination;
+import org.apache.qpid.client.AMQSession;
+import org.apache.qpid.client.AMQTopic;
+import org.apache.qpid.client.transport.TransportConnection;
+import org.apache.qpid.exchange.ExchangeDefaults;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageListener;
+import javax.jms.MessageProducer;
+import javax.jms.Session;
+
+public class MultipleConnectionTest extends TestCase
+{
+ private static final Logger _logger = LoggerFactory.getLogger(MultipleConnectionTest.class);
+
+ public static final String _defaultBroker = "vm://:1";
+ public String _connectionString = _defaultBroker;
+
+ private static class Receiver
+ {
+ private AMQConnection _connection;
+ private Session[] _sessions;
+ private MessageCounter[] _counters;
+
+ Receiver(String broker, AMQDestination dest, int sessions) throws Exception
+ {
+ this(new AMQConnection(broker, "guest", "guest", randomize("Client"), "test"), dest, sessions);
+ }
+
+ Receiver(AMQConnection connection, AMQDestination dest, int sessions) throws Exception
+ {
+ _connection = connection;
+ _sessions = new AMQSession[sessions];
+ _counters = new MessageCounter[sessions];
+ for (int i = 0; i < sessions; i++)
+ {
+ _sessions[i] = _connection.createSession(false, AMQSession.NO_ACKNOWLEDGE);
+ _counters[i] = new MessageCounter(_sessions[i].toString());
+ _sessions[i].createConsumer(dest).setMessageListener(_counters[i]);
+ }
+
+ _connection.start();
+ }
+
+ void close() throws JMSException
+ {
+ _connection.close();
+ }
+ }
+
+ private static class Publisher
+ {
+ private AMQConnection _connection;
+ private Session _session;
+ private MessageProducer _producer;
+
+ Publisher(String broker, AMQDestination dest) throws Exception
+ {
+ this(new AMQConnection(broker, "guest", "guest", randomize("Client"), "test"), dest);
+ }
+
+ Publisher(AMQConnection connection, AMQDestination dest) throws Exception
+ {
+ _connection = connection;
+ _session = _connection.createSession(false, AMQSession.NO_ACKNOWLEDGE);
+ _producer = _session.createProducer(dest);
+ }
+
+ void send(String msg) throws JMSException
+ {
+ _producer.send(_session.createTextMessage(msg));
+ }
+
+ void close() throws JMSException
+ {
+ _connection.close();
+ }
+ }
+
+ private static class MessageCounter implements MessageListener
+ {
+ private final String _name;
+ private int _count;
+
+ MessageCounter(String name)
+ {
+ _name = name;
+ }
+
+ public synchronized void onMessage(Message message)
+ {
+ _count++;
+ notify();
+ }
+
+ synchronized boolean waitUntil(int expected, long maxWait) throws InterruptedException
+ {
+ long start = System.currentTimeMillis();
+ while (expected > _count)
+ {
+ long timeLeft = maxWait - timeSince(start);
+ if (timeLeft < 0)
+ {
+ break;
+ }
+
+ wait(timeLeft);
+ }
+
+ return expected <= _count;
+ }
+
+ private long timeSince(long start)
+ {
+ return System.currentTimeMillis() - start;
+ }
+
+ public synchronized String toString()
+ {
+ return _name + ": " + _count;
+ }
+ }
+
+ 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++)
+ {
+ waitForCompletion(expected, wait, receivers[i]._counters);
+ }
+ }
+
+ private static void waitForCompletion(int expected, long wait, MessageCounter[] counters) throws InterruptedException
+ {
+ for (int i = 0; i < counters.length; i++)
+ {
+ if (!counters[i].waitUntil(expected, wait))
+ {
+ throw new RuntimeException("Expected: " + expected + " got " + counters[i]);
+ }
+ }
+ }
+
+ private static String randomize(String in)
+ {
+ return in + System.currentTimeMillis();
+ }
+
+ public static void main(String[] argv) throws Exception
+ {
+ String broker = (argv.length > 0) ? argv[0] : _defaultBroker;
+
+ MultipleConnectionTest test = new MultipleConnectionTest();
+ test._connectionString = broker;
+ test.test();
+ }
+
+ public void test() throws Exception
+ {
+ String broker = _connectionString;
+ int messages = 10;
+
+ AMQTopic topic = new AMQTopic(ExchangeDefaults.TOPIC_EXCHANGE_NAME, "amq.topic");
+
+ Receiver[] receivers = new Receiver[] { new Receiver(broker, topic, 2), new Receiver(broker, topic, 14) };
+
+ Publisher publisher = new Publisher(broker, topic);
+ for (int i = 0; i < messages; i++)
+ {
+ publisher.send("Message " + (i + 1));
+ }
+
+ try
+ {
+ waitForCompletion(messages, 5000, receivers);
+ _logger.info("All receivers received all expected messages");
+ }
+ finally
+ {
+ publisher.close();
+ for (int i = 0; i < receivers.length; i++)
+ {
+ receivers[i].close();
+ }
+ }
+ }
+
+ public static junit.framework.Test suite()
+ {
+ return new junit.framework.TestSuite(MultipleConnectionTest.class);
+ }
+}
diff --git a/Final/java/client/src/test/java/org/apache/qpid/test/unit/basic/ObjectMessageTest.java b/Final/java/client/src/test/java/org/apache/qpid/test/unit/basic/ObjectMessageTest.java
new file mode 100644
index 0000000000..9237555734
--- /dev/null
+++ b/Final/java/client/src/test/java/org/apache/qpid/test/unit/basic/ObjectMessageTest.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.test.unit.basic;
+
+import junit.framework.Assert;
+import junit.framework.TestCase;
+
+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.message.JMSObjectMessage;
+import org.apache.qpid.client.transport.TransportConnection;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageListener;
+import javax.jms.MessageNotWriteableException;
+import javax.jms.MessageProducer;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+public class ObjectMessageTest extends TestCase implements MessageListener
+{
+ private static final Logger _logger = LoggerFactory.getLogger(ObjectMessageTest.class);
+
+ private AMQConnection _connection;
+ private AMQDestination _destination;
+ private AMQSession _session;
+ private final List<JMSObjectMessage> received = new ArrayList<JMSObjectMessage>();
+ private final List<Payload> messages = new ArrayList<Payload>();
+ private int _count = 100;
+ public String _connectionString = "vm://:1";
+
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+ TransportConnection.createVMBroker(1);
+ try
+ {
+ init(new AMQConnection(_connectionString, "guest", "guest", randomize("Client"), "test"));
+ }
+ catch (Exception e)
+ {
+ fail("Uable to initialise: " + e);
+ }
+ }
+
+ protected void tearDown() throws Exception
+ {
+ super.tearDown();
+ TransportConnection.killAllVMBrokers();
+ }
+
+ private void init(AMQConnection connection) throws Exception
+ {
+ init(connection, new AMQQueue(connection, randomize("ObjectMessageTest"), true));
+ }
+
+ private void init(AMQConnection connection, AMQDestination destination) throws Exception
+ {
+ _connection = connection;
+ _destination = destination;
+ _session = (AMQSession) connection.createSession(false, AMQSession.NO_ACKNOWLEDGE);
+
+ // set up a slow consumer
+ _session.createConsumer(destination).setMessageListener(this);
+ connection.start();
+ }
+
+ public void test() throws Exception
+ {
+ int count = _count;
+ send(count);
+ waitFor(count);
+ check();
+ _logger.info("Completed without failure");
+ _connection.close();
+ }
+
+ void send(int count) throws JMSException
+ {
+ // create a publisher
+ MessageProducer producer = _session.createProducer(_destination);
+ for (int i = 0; i < count; i++)
+ {
+ Payload payload = new Payload("Message " + i);
+ messages.add(payload);
+ producer.send(_session.createObjectMessage(payload));
+ }
+ }
+
+ void waitFor(int count) throws InterruptedException
+ {
+ synchronized (received)
+ {
+ while (received.size() < count)
+ {
+ received.wait();
+ }
+ }
+ }
+
+ void check() throws JMSException
+ {
+ List<Object> actual = new ArrayList<Object>();
+ for (JMSObjectMessage m : received)
+ {
+ actual.add(m.getObject());
+
+ try
+ {
+ m.setObject("Test text");
+ Assert.fail("Message should not be writeable");
+ }
+ catch (MessageNotWriteableException mnwe)
+ {
+ // normal execution
+ }
+
+ m.clearBody();
+
+ try
+ {
+ m.setObject("Test text");
+ }
+ catch (MessageNotWriteableException mnwe)
+ {
+ Assert.fail("Message should be writeable");
+ }
+
+ // Check property write status
+ try
+ {
+ m.setStringProperty("test", "test");
+ Assert.fail("Message should not be writeable");
+ }
+ catch (MessageNotWriteableException mnwe)
+ {
+ // normal execution
+ }
+
+ m.clearProperties();
+
+ try
+ {
+ m.setStringProperty("test", "test");
+ }
+ catch (MessageNotWriteableException mnwe)
+ {
+ Assert.fail("Message should be writeable");
+ }
+
+ }
+
+ assertEqual(messages.iterator(), actual.iterator());
+
+ }
+
+ private static void assertEqual(Iterator expected, Iterator actual)
+ {
+ List<String> errors = new ArrayList<String>();
+ while (expected.hasNext() && actual.hasNext())
+ {
+ try
+ {
+ assertEqual(expected.next(), actual.next());
+ }
+ catch (Exception e)
+ {
+ errors.add(e.getMessage());
+ }
+ }
+ while (expected.hasNext())
+ {
+ errors.add("Expected " + expected.next() + " but no more actual values.");
+ }
+ while (actual.hasNext())
+ {
+ errors.add("Found " + actual.next() + " but no more expected values.");
+ }
+
+ if (!errors.isEmpty())
+ {
+ throw new RuntimeException(errors.toString());
+ }
+ }
+
+ private static void assertEqual(Object expected, Object actual)
+ {
+ if (!expected.equals(actual))
+ {
+ throw new RuntimeException("Expected '" + expected + "' found '" + actual + "'");
+ }
+ }
+
+ public void onMessage(Message message)
+ {
+ synchronized (received)
+ {
+ received.add((JMSObjectMessage) message);
+ received.notify();
+ }
+ }
+
+ private static String randomize(String in)
+ {
+ return in + System.currentTimeMillis();
+ }
+
+ private static class Payload implements Serializable
+ {
+ private final String data;
+
+ Payload(String data)
+ {
+ this.data = data;
+ }
+
+ public int hashCode()
+ {
+ return data.hashCode();
+ }
+
+ public boolean equals(Object o)
+ {
+ return (o instanceof Payload) && ((Payload) o).data.equals(data);
+ }
+
+ public String toString()
+ {
+ return "Payload[" + data + "]";
+ }
+ }
+
+ public static void main(String[] argv) throws Exception
+ {
+ ObjectMessageTest test = new ObjectMessageTest();
+ test._connectionString = (argv.length == 0) ? "vm://:1" : argv[0];
+ test.setUp();
+ if (argv.length > 1)
+ {
+ test._count = Integer.parseInt(argv[1]);
+ }
+
+ test.test();
+ }
+
+ public static junit.framework.Test suite()
+ {
+ return new junit.framework.TestSuite(ObjectMessageTest.class);
+ }
+}
diff --git a/Final/java/client/src/test/java/org/apache/qpid/test/unit/basic/PropertyValueTest.java b/Final/java/client/src/test/java/org/apache/qpid/test/unit/basic/PropertyValueTest.java
new file mode 100644
index 0000000000..dce9667ff2
--- /dev/null
+++ b/Final/java/client/src/test/java/org/apache/qpid/test/unit/basic/PropertyValueTest.java
@@ -0,0 +1,369 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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 junit.framework.Assert;
+import junit.framework.TestCase;
+
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.client.AMQQueue;
+import org.apache.qpid.client.AMQSession;
+import org.apache.qpid.client.message.AMQMessage;
+import org.apache.qpid.client.message.JMSTextMessage;
+import org.apache.qpid.client.transport.TransportConnection;
+import org.apache.qpid.framing.AMQShortString;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.jms.Destination;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageListener;
+import javax.jms.MessageProducer;
+import javax.jms.Queue;
+import javax.jms.Session;
+
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+public class PropertyValueTest extends TestCase implements MessageListener
+{
+ private static final Logger _logger = LoggerFactory.getLogger(PropertyValueTest.class);
+
+ private int count = 0;
+ private AMQConnection _connection;
+ private Destination _destination;
+ private AMQSession _session;
+ private final List<JMSTextMessage> received = new ArrayList<JMSTextMessage>();
+ private final List<String> messages = new ArrayList<String>();
+ private int _count = 1;
+ public String _connectionString = "vm://:1";
+
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+ TransportConnection.createVMBroker(1);
+ }
+
+ protected void tearDown() throws Exception
+ {
+ super.tearDown();
+ TransportConnection.killVMBroker(1);
+ }
+
+ private void init(AMQConnection connection) throws Exception
+ {
+ Destination destination = new AMQQueue(connection, randomize("PropertyValueTest"), true);
+ init(connection, destination);
+ }
+
+ private void init(AMQConnection connection, Destination destination) throws Exception
+ {
+ _connection = connection;
+ _destination = destination;
+ _session = (AMQSession) connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ // set up a slow consumer
+ _session.createConsumer(destination).setMessageListener(this);
+ connection.start();
+ }
+
+ public void testOnce()
+ {
+ runBatch(1);
+ }
+
+ public void test50()
+ {
+ runBatch(50);
+ }
+
+ private void runBatch(int runSize)
+ {
+ try
+ {
+ int run = 0;
+ while (run < runSize)
+ {
+ _logger.error("Run Number:" + run++);
+ try
+ {
+ init(new AMQConnection(_connectionString, "guest", "guest", randomize("Client"), "test"));
+ }
+ catch (Exception e)
+ {
+ fail("Unable to initialilse connection: " + e);
+ }
+
+ int count = _count;
+ send(count);
+ waitFor(count);
+ check();
+ _logger.info("Completed without failure");
+
+ Thread.sleep(10);
+ _connection.close();
+
+ _logger.error("End Run Number:" + (run - 1));
+ }
+ }
+ catch (Exception e)
+ {
+ _logger.error(e.getMessage(), e);
+ e.printStackTrace();
+ }
+ }
+
+ void send(int count) throws JMSException
+ {
+ // create a publisher
+ MessageProducer producer = _session.createProducer(_destination);
+ for (int i = 0; i < count; i++)
+ {
+ String text = "Message " + i;
+ messages.add(text);
+ Message m = _session.createTextMessage(text);
+
+ m.setBooleanProperty("Bool", true);
+
+ m.setByteProperty("Byte", (byte) Byte.MAX_VALUE);
+ m.setDoubleProperty("Double", (double) Double.MAX_VALUE);
+ m.setFloatProperty("Float", (float) Float.MAX_VALUE);
+ m.setIntProperty("Int", (int) Integer.MAX_VALUE);
+
+ m.setJMSCorrelationID("Correlation");
+ // fixme the m.setJMSMessage has no effect
+ producer.setPriority(8);
+ m.setJMSPriority(3);
+
+ // Queue
+ Queue q;
+
+ if ((i / 2) == 0)
+ {
+ q = _session.createTemporaryQueue();
+ }
+ else
+ {
+ q = new AMQQueue(_connection, "TestReply");
+ }
+
+ m.setJMSReplyTo(q);
+ m.setStringProperty("TempQueue", q.toString());
+
+ _logger.trace("Message:" + m);
+
+ Assert.assertEquals("Check temp queue has been set correctly", m.getJMSReplyTo().toString(),
+ m.getStringProperty("TempQueue"));
+
+ m.setJMSType("Test");
+ m.setLongProperty("UnsignedInt", (long) 4294967295L);
+ m.setLongProperty("Long", (long) Long.MAX_VALUE);
+
+ m.setShortProperty("Short", (short) Short.MAX_VALUE);
+ m.setStringProperty("String", "Test");
+
+ // AMQP Specific values
+
+ // Timestamp
+ long nano = System.nanoTime();
+ m.setStringProperty("time-str", String.valueOf(nano));
+ ((AMQMessage) m).setTimestampProperty(new AMQShortString("time"), nano);
+
+ // Decimal
+ BigDecimal bd = new BigDecimal(Integer.MAX_VALUE);
+ ((AMQMessage) m).setDecimalProperty(new AMQShortString("decimal"), bd.setScale(Byte.MAX_VALUE));
+
+ bd = new BigDecimal((long) Integer.MAX_VALUE + 1L);
+
+ try
+ {
+ ((AMQMessage) m).setDecimalProperty(new AMQShortString("decimal-bad-value"), bd.setScale(Byte.MAX_VALUE));
+ fail("UnsupportedOperationException should be thrown as value can't be correctly transmitted");
+ }
+ catch (UnsupportedOperationException uoe)
+ {
+ // normal path.
+ }
+
+ try
+ {
+ ((AMQMessage) m).setDecimalProperty(new AMQShortString("decimal-bad-scale"),
+ bd.setScale(Byte.MAX_VALUE + 1));
+ fail("UnsupportedOperationException should be thrown as scale can't be correctly transmitted");
+ }
+ catch (UnsupportedOperationException uoe)
+ {
+ // normal path.
+ }
+
+ // Void
+ ((AMQMessage) m).setVoidProperty(new AMQShortString("void"));
+
+ _logger.debug("Sending Msg:" + m);
+ producer.send(m);
+ }
+ }
+
+ void waitFor(int count) throws InterruptedException
+ {
+ synchronized (received)
+ {
+ while (received.size() < count)
+ {
+ received.wait();
+ }
+ }
+ }
+
+ void check() throws JMSException
+ {
+ List<String> actual = new ArrayList<String>();
+ for (JMSTextMessage m : received)
+ {
+ actual.add(m.getText());
+
+ // Check Properties
+
+ Assert.assertEquals("Check Boolean properties are correctly transported", true, m.getBooleanProperty("Bool"));
+ Assert.assertEquals("Check Byte properties are correctly transported", (byte) Byte.MAX_VALUE,
+ m.getByteProperty("Byte"));
+ Assert.assertEquals("Check Double properties are correctly transported", (double) Double.MAX_VALUE,
+ m.getDoubleProperty("Double"));
+ Assert.assertEquals("Check Float properties are correctly transported", (float) Float.MAX_VALUE,
+ m.getFloatProperty("Float"));
+ Assert.assertEquals("Check Int properties are correctly transported", (int) Integer.MAX_VALUE,
+ m.getIntProperty("Int"));
+ Assert.assertEquals("Check CorrelationID properties are correctly transported", "Correlation",
+ m.getJMSCorrelationID());
+ Assert.assertEquals("Check Priority properties are correctly transported", 8, m.getJMSPriority());
+
+ // Queue
+ Assert.assertEquals("Check ReplyTo properties are correctly transported", m.getStringProperty("TempQueue"),
+ m.getJMSReplyTo().toString());
+
+ Assert.assertEquals("Check Type properties are correctly transported", "Test", m.getJMSType());
+
+ Assert.assertEquals("Check Short properties are correctly transported", (short) Short.MAX_VALUE,
+ m.getShortProperty("Short"));
+ Assert.assertEquals("Check UnsignedInt properties are correctly transported", (long) 4294967295L,
+ m.getLongProperty("UnsignedInt"));
+ Assert.assertEquals("Check Long properties are correctly transported", (long) Long.MAX_VALUE,
+ m.getLongProperty("Long"));
+ Assert.assertEquals("Check String properties are correctly transported", "Test", m.getStringProperty("String"));
+
+ // AMQP Tests Specific values
+
+ Assert.assertEquals("Check Timestamp properties are correctly transported", m.getStringProperty("time-str"),
+ ((AMQMessage) m).getTimestampProperty(new AMQShortString("time")).toString());
+
+ // Decimal
+ BigDecimal bd = new BigDecimal(Integer.MAX_VALUE);
+
+ Assert.assertEquals("Check decimal properties are correctly transported", bd.setScale(Byte.MAX_VALUE),
+ ((AMQMessage) m).getDecimalProperty(new AMQShortString("decimal")));
+
+ // Void
+ ((AMQMessage) m).setVoidProperty(new AMQShortString("void"));
+
+ Assert.assertTrue("Check void properties are correctly transported",
+ ((AMQMessage) m).getPropertyHeaders().containsKey("void"));
+ }
+
+ received.clear();
+
+ assertEqual(messages.iterator(), actual.iterator());
+
+ messages.clear();
+ }
+
+ private static void assertEqual(Iterator expected, Iterator actual)
+ {
+ List<String> errors = new ArrayList<String>();
+ while (expected.hasNext() && actual.hasNext())
+ {
+ try
+ {
+ assertEqual(expected.next(), actual.next());
+ }
+ catch (Exception e)
+ {
+ errors.add(e.getMessage());
+ }
+ }
+ while (expected.hasNext())
+ {
+ errors.add("Expected " + expected.next() + " but no more actual values.");
+ }
+ while (actual.hasNext())
+ {
+ errors.add("Found " + actual.next() + " but no more expected values.");
+ }
+
+ if (!errors.isEmpty())
+ {
+ throw new RuntimeException(errors.toString());
+ }
+ }
+
+ private static void assertEqual(Object expected, Object actual)
+ {
+ if (!expected.equals(actual))
+ {
+ throw new RuntimeException("Expected '" + expected + "' found '" + actual + "'");
+ }
+ }
+
+ public void onMessage(Message message)
+ {
+ synchronized (received)
+ {
+ received.add((JMSTextMessage) message);
+ received.notify();
+ }
+ }
+
+ private static String randomize(String in)
+ {
+ return in + System.currentTimeMillis();
+ }
+
+ public static void main(String[] argv) throws Exception
+ {
+ PropertyValueTest test = new PropertyValueTest();
+ test._connectionString = (argv.length == 0) ? "vm://:1" : argv[0];
+ test.setUp();
+ if (argv.length > 1)
+ {
+ test._count = Integer.parseInt(argv[1]);
+ }
+
+ test.testOnce();
+ }
+
+ public static junit.framework.Test suite()
+ {
+ return new junit.framework.TestSuite(PropertyValueTest.class);
+ }
+}
diff --git a/Final/java/client/src/test/java/org/apache/qpid/test/unit/basic/PubSubTwoConnectionTest.java b/Final/java/client/src/test/java/org/apache/qpid/test/unit/basic/PubSubTwoConnectionTest.java
new file mode 100644
index 0000000000..a3d0cf6dcd
--- /dev/null
+++ b/Final/java/client/src/test/java/org/apache/qpid/test/unit/basic/PubSubTwoConnectionTest.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.test.unit.basic;
+
+import javax.jms.Connection;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageProducer;
+import javax.jms.Session;
+import javax.jms.TextMessage;
+import javax.jms.Topic;
+
+import junit.framework.TestCase;
+
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.client.AMQSession;
+import org.apache.qpid.client.AMQTopic;
+import org.apache.qpid.client.transport.TransportConnection;
+
+/**
+ * @author Apache Software Foundation
+ */
+public class PubSubTwoConnectionTest extends TestCase
+{
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+ TransportConnection.createVMBroker(1);
+ }
+
+ protected void tearDown() throws Exception
+ {
+ super.tearDown();
+ TransportConnection.killAllVMBrokers();
+ }
+
+ /**
+ * This tests that a consumer is set up synchronously
+ * @throws Exception
+ */
+ public void testTwoConnections() throws Exception
+ {
+
+ AMQConnection con1 = new AMQConnection("vm://:1", "guest", "guest", "Client1", "test");
+
+ Topic topic = new AMQTopic(con1, "MyTopic");
+
+ Session session1 = con1.createSession(false, AMQSession.NO_ACKNOWLEDGE);
+ MessageProducer producer = session1.createProducer(topic);
+
+ Connection con2 = new AMQConnection("vm://:1", "guest", "guest", "Client2", "test");
+ Session session2 = con2.createSession(false, AMQSession.NO_ACKNOWLEDGE);
+ MessageConsumer consumer = session2.createConsumer(topic);
+ con2.start();
+ producer.send(session1.createTextMessage("Hello"));
+ TextMessage tm1 = (TextMessage) consumer.receive(2000);
+ assertNotNull(tm1);
+ assertEquals("Hello", tm1.getText());
+ }
+}
diff --git a/Final/java/client/src/test/java/org/apache/qpid/test/unit/basic/ReceiveTest.java b/Final/java/client/src/test/java/org/apache/qpid/test/unit/basic/ReceiveTest.java
new file mode 100644
index 0000000000..668233f356
--- /dev/null
+++ b/Final/java/client/src/test/java/org/apache/qpid/test/unit/basic/ReceiveTest.java
@@ -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.
+ *
+ */
+package org.apache.qpid.test.unit.basic;
+
+import javax.jms.MessageConsumer;
+
+import junit.framework.TestCase;
+
+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.transport.TransportConnection;
+import org.apache.qpid.client.vmbroker.AMQVMBrokerCreationException;
+
+public class ReceiveTest extends TestCase
+{
+ private AMQConnection _connection;
+ private AMQDestination _destination;
+ private AMQSession _session;
+ private MessageConsumer _consumer;
+
+ private static final String VM_BROKER = "vm://:1";
+ public String _connectionString = VM_BROKER;
+
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+ if (_connectionString.equals(VM_BROKER))
+ {
+ createVMBroker();
+ String broker = _connectionString;
+ init(new AMQConnection(broker, "guest", "guest", "ReceiveTestClient", "test"));
+ }
+ }
+
+ public void createVMBroker()
+ {
+ try
+ {
+ TransportConnection.createVMBroker(1);
+ }
+ catch (AMQVMBrokerCreationException e)
+ {
+ fail("Unable to create broker: " + e);
+ }
+ }
+
+ protected void tearDown() throws Exception
+ {
+ if (_connectionString.equals(VM_BROKER))
+ {
+ TransportConnection.killVMBroker(1);
+ }
+ super.tearDown();
+ }
+
+ private void init(AMQConnection connection) throws Exception
+ {
+ init(connection, new AMQQueue(connection,"ReceiveTest", true));
+ }
+
+ private void init(AMQConnection connection, AMQDestination destination) throws Exception
+ {
+ _connection = connection;
+ _destination = destination;
+ _session = (AMQSession) connection.createSession(true, AMQSession.NO_ACKNOWLEDGE);
+ _consumer = _session.createConsumer(_destination);
+ _connection.start();
+ }
+
+ public void test() throws Exception
+ {
+ _consumer.receive(5000);
+ _connection.close();
+ }
+
+ public static void main(String[] argv) throws Exception
+ {
+ ReceiveTest test = new ReceiveTest();
+ test._connectionString = argv.length == 0 ? VM_BROKER : argv[0];
+ test.setUp();
+ test.test();
+ test.tearDown();
+ }
+
+ public static junit.framework.Test suite()
+ {
+ // TODO: note that this test doesn't use the VMBrokerSetup
+ // test helper class to create and tear down its
+ // VMBroker. This is because the main() above seems to
+ // indicate that it's also used outside of the surefire test
+ // framework. If it isn't, then this test should also be
+ // changed to use VMBrokerSetup here.
+ return new junit.framework.TestSuite(ReceiveTest.class);
+ }
+}
diff --git a/Final/java/client/src/test/java/org/apache/qpid/test/unit/basic/SelectorTest.java b/Final/java/client/src/test/java/org/apache/qpid/test/unit/basic/SelectorTest.java
new file mode 100644
index 0000000000..40c712c1c9
--- /dev/null
+++ b/Final/java/client/src/test/java/org/apache/qpid/test/unit/basic/SelectorTest.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.test.unit.basic;
+
+import junit.framework.TestCase;
+
+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.transport.TransportConnection;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.jms.DeliveryMode;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageListener;
+
+public class SelectorTest extends TestCase 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";
+
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+ TransportConnection.createVMBroker(1);
+ init(new AMQConnection(_connectionString, "guest", "guest", randomize("Client"), "test"));
+ }
+
+ protected void tearDown() throws Exception
+ {
+ super.tearDown();
+ TransportConnection.killAllVMBrokers();
+ }
+
+ private void init(AMQConnection connection) throws Exception
+ {
+ init(connection, new AMQQueue(connection, randomize("SessionStartTest"), true));
+ }
+
+ private void init(AMQConnection connection, AMQDestination destination) throws Exception
+ {
+ _connection = connection;
+ _destination = destination;
+ connection.start();
+
+ String selector = null;
+ // selector = "Cost = 2 AND JMSDeliveryMode=" + DeliveryMode.NON_PERSISTENT;
+ // 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 synchronized void test() throws JMSException, InterruptedException
+ {
+ try
+ {
+ Message msg = _session.createTextMessage("Message");
+ msg.setJMSPriority(1);
+ msg.setIntProperty("Cost", 2);
+ msg.setJMSType("Special");
+
+ _logger.info("Sending Message:" + msg);
+
+ ((BasicMessageProducer) _session.createProducer(_destination)).send(msg, DeliveryMode.NON_PERSISTENT);
+ _logger.info("Message sent, waiting for response...");
+ wait(1000);
+
+ if (count > 0)
+ {
+ _logger.info("Got message");
+ }
+
+ if (count == 0)
+ {
+ fail("Did not get message!");
+ // throw new RuntimeException("Did not get message!");
+ }
+ }
+ finally
+ {
+ _session.close();
+ _connection.close();
+ }
+ }
+
+ public synchronized void onMessage(Message message)
+ {
+ count++;
+ _logger.info("Got Message:" + message);
+ notify();
+ }
+
+ 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:5672" : argv[0];
+ test.setUp();
+ test.test();
+ }
+
+ public static junit.framework.Test suite()
+ {
+ return new junit.framework.TestSuite(SelectorTest.class);
+ }
+}
diff --git a/Final/java/client/src/test/java/org/apache/qpid/test/unit/basic/SessionStartTest.java b/Final/java/client/src/test/java/org/apache/qpid/test/unit/basic/SessionStartTest.java
new file mode 100644
index 0000000000..cc18169a5b
--- /dev/null
+++ b/Final/java/client/src/test/java/org/apache/qpid/test/unit/basic/SessionStartTest.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.basic;
+
+import junit.framework.TestCase;
+
+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.framing.AMQShortString;
+import org.apache.qpid.testutil.VMBrokerSetup;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageListener;
+
+public class SessionStartTest extends TestCase implements MessageListener
+{
+ private static final Logger _logger = LoggerFactory.getLogger(SessionStartTest.class);
+
+ private AMQConnection _connection;
+ private AMQDestination _destination;
+ private AMQSession _session;
+ private int count;
+ public String _connectionString = "vm://:1";
+
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+ init(new AMQConnection(_connectionString, "guest", "guest", randomize("Client"), "test"));
+ }
+
+ protected void tearDown() throws Exception
+ {
+ super.tearDown();
+ }
+
+ private void init(AMQConnection connection) throws Exception
+ {
+ init(connection,
+ new AMQQueue(connection.getDefaultQueueExchangeName(), new AMQShortString(randomize("SessionStartTest")), true));
+ }
+
+ private void init(AMQConnection connection, AMQDestination destination) throws Exception
+ {
+ _connection = connection;
+ _destination = destination;
+ connection.start();
+
+ _session = (AMQSession) connection.createSession(false, AMQSession.NO_ACKNOWLEDGE);
+ _session.createConsumer(destination).setMessageListener(this);
+ }
+
+ public synchronized void test() throws JMSException, InterruptedException
+ {
+ try
+ {
+ _session.createProducer(_destination).send(_session.createTextMessage("Message"));
+ _logger.info("Message sent, waiting for response...");
+ wait(1000);
+ if (count > 0)
+ {
+ _logger.info("Got message");
+ }
+ else
+ {
+ throw new RuntimeException("Did not get message!");
+ }
+ }
+ finally
+ {
+ _session.close();
+ _connection.close();
+ }
+ }
+
+ public synchronized void onMessage(Message message)
+ {
+ count++;
+ notify();
+ }
+
+ private static String randomize(String in)
+ {
+ return in + System.currentTimeMillis();
+ }
+
+ public static void main(String[] argv) throws Exception
+ {
+ SessionStartTest test = new SessionStartTest();
+ test._connectionString = (argv.length == 0) ? "localhost:5672" : argv[0];
+ test.setUp();
+ test.test();
+ }
+
+ public static junit.framework.Test suite()
+ {
+ return new VMBrokerSetup(new junit.framework.TestSuite(SessionStartTest.class));
+ }
+}
diff --git a/Final/java/client/src/test/java/org/apache/qpid/test/unit/basic/TextMessageTest.java b/Final/java/client/src/test/java/org/apache/qpid/test/unit/basic/TextMessageTest.java
new file mode 100644
index 0000000000..000fb9ab88
--- /dev/null
+++ b/Final/java/client/src/test/java/org/apache/qpid/test/unit/basic/TextMessageTest.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.test.unit.basic;
+
+import junit.framework.Assert;
+import junit.framework.TestCase;
+
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.client.AMQQueue;
+import org.apache.qpid.client.AMQSession;
+import org.apache.qpid.client.message.JMSTextMessage;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.testutil.VMBrokerSetup;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.jms.Destination;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageListener;
+import javax.jms.MessageNotWriteableException;
+import javax.jms.MessageProducer;
+import javax.jms.Session;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+public class TextMessageTest extends TestCase implements MessageListener
+{
+ private static final Logger _logger = LoggerFactory.getLogger(TextMessageTest.class);
+
+ private AMQConnection _connection;
+ private Destination _destination;
+ private AMQSession _session;
+ private final List<JMSTextMessage> received = new ArrayList<JMSTextMessage>();
+ private final List<String> messages = new ArrayList<String>();
+ private int _count = 100;
+ public String _connectionString = "vm://:1";
+
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+ try
+ {
+ init(new AMQConnection(_connectionString, "guest", "guest", randomize("Client"), "test"));
+ }
+ catch (Exception e)
+ {
+ fail("Unable to initialilse connection: " + e);
+ }
+ }
+
+ protected void tearDown() throws Exception
+ {
+ super.tearDown();
+ }
+
+ private void init(AMQConnection connection) throws Exception
+ {
+ Destination destination =
+ new AMQQueue(connection.getDefaultQueueExchangeName(), new AMQShortString(randomize("TextMessageTest")), true);
+ init(connection, destination);
+ }
+
+ private void init(AMQConnection connection, Destination destination) throws Exception
+ {
+ _connection = connection;
+ _destination = destination;
+ _session = (AMQSession) connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ // set up a slow consumer
+ _session.createConsumer(destination).setMessageListener(this);
+ connection.start();
+ }
+
+ public void test() throws Exception
+ {
+ int count = _count;
+ send(count);
+ waitFor(count);
+ check();
+ _logger.info("Completed without failure");
+ _connection.close();
+ }
+
+ void send(int count) throws JMSException
+ {
+ // create a publisher
+ MessageProducer producer = _session.createProducer(_destination);
+ for (int i = 0; i < count; i++)
+ {
+ String text = "Message " + i;
+ messages.add(text);
+ Message m = _session.createTextMessage(text);
+ m.setStringProperty("String", "hello");
+
+ _logger.info("Sending Msg:" + m);
+ producer.send(m);
+ }
+ }
+
+ void waitFor(int count) throws InterruptedException
+ {
+ synchronized (received)
+ {
+ while (received.size() < count)
+ {
+ received.wait();
+ }
+ }
+ }
+
+ void check() throws JMSException
+ {
+ List<String> actual = new ArrayList<String>();
+ for (JMSTextMessage m : received)
+ {
+ actual.add(m.getText());
+
+ // Check body write status
+ try
+ {
+ m.setText("Test text");
+ Assert.fail("Message should not be writeable");
+ }
+ catch (MessageNotWriteableException mnwe)
+ {
+ // normal execution
+ }
+
+ m.clearBody();
+
+ try
+ {
+ m.setText("Test text");
+ }
+ catch (MessageNotWriteableException mnwe)
+ {
+ Assert.fail("Message should be writeable");
+ }
+
+ // Check property write status
+ try
+ {
+ m.setStringProperty("test", "test");
+ Assert.fail("Message should not be writeable");
+ }
+ catch (MessageNotWriteableException mnwe)
+ {
+ // normal execution
+ }
+
+ m.clearProperties();
+
+ try
+ {
+ m.setStringProperty("test", "test");
+ }
+ catch (MessageNotWriteableException mnwe)
+ {
+ Assert.fail("Message should be writeable");
+ }
+
+ }
+
+ assertEqual(messages.iterator(), actual.iterator());
+ }
+
+ private static void assertEqual(Iterator expected, Iterator actual)
+ {
+ List<String> errors = new ArrayList<String>();
+ while (expected.hasNext() && actual.hasNext())
+ {
+ try
+ {
+ assertEqual(expected.next(), actual.next());
+ }
+ catch (Exception e)
+ {
+ errors.add(e.getMessage());
+ }
+ }
+ while (expected.hasNext())
+ {
+ errors.add("Expected " + expected.next() + " but no more actual values.");
+ }
+ while (actual.hasNext())
+ {
+ errors.add("Found " + actual.next() + " but no more expected values.");
+ }
+
+ if (!errors.isEmpty())
+ {
+ throw new RuntimeException(errors.toString());
+ }
+ }
+
+ private static void assertEqual(Object expected, Object actual)
+ {
+ if (!expected.equals(actual))
+ {
+ throw new RuntimeException("Expected '" + expected + "' found '" + actual + "'");
+ }
+ }
+
+ public void onMessage(Message message)
+ {
+ synchronized (received)
+ {
+ received.add((JMSTextMessage) message);
+ received.notify();
+ }
+ }
+
+ private static String randomize(String in)
+ {
+ return in + System.currentTimeMillis();
+ }
+
+ public static void main(String[] argv) throws Exception
+ {
+ TextMessageTest test = new TextMessageTest();
+ test._connectionString = (argv.length == 0) ? "vm://:1" : argv[0];
+ test.setUp();
+ if (argv.length > 1)
+ {
+ test._count = Integer.parseInt(argv[1]);
+ }
+
+ test.test();
+ }
+
+ public static junit.framework.Test suite()
+ {
+ return new VMBrokerSetup(new junit.framework.TestSuite(TextMessageTest.class));
+ }
+}
diff --git a/Final/java/client/src/test/java/org/apache/qpid/test/unit/basic/close/CloseTests.java b/Final/java/client/src/test/java/org/apache/qpid/test/unit/basic/close/CloseTests.java
new file mode 100644
index 0000000000..690ba7f01b
--- /dev/null
+++ b/Final/java/client/src/test/java/org/apache/qpid/test/unit/basic/close/CloseTests.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.test.unit.basic.close;
+
+import junit.framework.TestCase;
+
+import org.apache.qpid.AMQException;
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.client.AMQQueue;
+import org.apache.qpid.client.transport.TransportConnection;
+import org.apache.qpid.url.AMQBindingURL;
+import org.apache.qpid.url.URLSyntaxException;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.jms.JMSException;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageProducer;
+import javax.jms.Session;
+
+public class CloseTests extends TestCase
+{
+ private static final Logger _logger = LoggerFactory.getLogger(CloseTests.class);
+
+ private static final String BROKER = "vm://:1";
+
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+
+ TransportConnection.createVMBroker(1);
+ }
+
+ protected void tearDown() throws Exception
+ {
+ super.setUp();
+
+ TransportConnection.killVMBroker(1);
+ }
+
+ public void testCloseQueueReceiver() throws AMQException, URLSyntaxException, JMSException
+ {
+ AMQConnection connection = new AMQConnection(BROKER, "guest", "guest", this.getName(), "test");
+
+ Session session = connection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ AMQQueue queue = new AMQQueue(new AMQBindingURL("test-queue"));
+ MessageConsumer consumer = session.createConsumer(queue);
+
+ MessageProducer producer_not_used_but_created_for_testing = session.createProducer(queue);
+
+ connection.start();
+
+ _logger.info("About to close consumer");
+
+ consumer.close();
+
+ _logger.info("Closed Consumer");
+
+ }
+}
diff --git a/Final/java/client/src/test/java/org/apache/qpid/test/unit/client/AMQConnectionTest.java b/Final/java/client/src/test/java/org/apache/qpid/test/unit/client/AMQConnectionTest.java
new file mode 100644
index 0000000000..0e15341615
--- /dev/null
+++ b/Final/java/client/src/test/java/org/apache/qpid/test/unit/client/AMQConnectionTest.java
@@ -0,0 +1,205 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.test.unit.client;
+
+import javax.jms.JMSException;
+import javax.jms.QueueSession;
+import javax.jms.TopicSession;
+
+import junit.framework.TestCase;
+
+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.transport.TransportConnection;
+import org.apache.qpid.framing.AMQShortString;
+
+public class AMQConnectionTest extends TestCase
+{
+ private static AMQConnection _connection;
+ private static AMQTopic _topic;
+ private static AMQQueue _queue;
+ private static QueueSession _queueSession;
+ private static TopicSession _topicSession;
+
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+ TransportConnection.createVMBroker(1);
+ _connection = new AMQConnection("vm://:1", "guest", "guest", "fred", "test");
+ _topic = new AMQTopic(_connection.getDefaultTopicExchangeName(), new AMQShortString("mytopic"));
+ _queue = new AMQQueue(_connection.getDefaultQueueExchangeName(), new AMQShortString("myqueue"));
+ }
+
+ protected void tearDown() throws Exception
+ {
+ super.tearDown();
+ try
+ {
+ _connection.close();
+ }
+ catch (JMSException e)
+ {
+ //ignore
+ }
+ TransportConnection.killAllVMBrokers();
+ }
+
+ /**
+ * Simple tests to check we can create TopicSession and QueueSession ok
+ * And that they throw exceptions where appropriate as per JMS spec
+ */
+
+ public void testCreateQueueSession() throws JMSException
+ {
+ _queueSession = _connection.createQueueSession(false, AMQSession.NO_ACKNOWLEDGE);
+ }
+
+ public void testCreateTopicSession() throws JMSException
+ {
+ _topicSession = _connection.createTopicSession(false, AMQSession.NO_ACKNOWLEDGE);
+ }
+
+ public void testTopicSessionCreateBrowser() throws JMSException
+ {
+ try
+ {
+ _topicSession.createBrowser(_queue);
+ fail("expected exception did not occur");
+ }
+ catch (javax.jms.IllegalStateException s)
+ {
+ // ok
+ }
+ catch (Exception e)
+ {
+ fail("expected javax.jms.IllegalStateException, got " + e);
+ }
+ }
+
+ public void testTopicSessionCreateQueue() throws JMSException
+ {
+ try
+ {
+ _topicSession.createQueue("abc");
+ fail("expected exception did not occur");
+ }
+ catch (javax.jms.IllegalStateException s)
+ {
+ // ok
+ }
+ catch (Exception e)
+ {
+ fail("expected javax.jms.IllegalStateException, got " + e);
+ }
+ }
+
+ public void testTopicSessionCreateTemporaryQueue() throws JMSException
+ {
+ try
+ {
+ _topicSession.createTemporaryQueue();
+ fail("expected exception did not occur");
+ }
+ catch (javax.jms.IllegalStateException s)
+ {
+ // ok
+ }
+ catch (Exception e)
+ {
+ fail("expected javax.jms.IllegalStateException, got " + e);
+ }
+ }
+
+ public void testQueueSessionCreateTemporaryTopic() throws JMSException
+ {
+ try
+ {
+ _queueSession.createTemporaryTopic();
+ fail("expected exception did not occur");
+ }
+ catch (javax.jms.IllegalStateException s)
+ {
+ // ok
+ }
+ catch (Exception e)
+ {
+ fail("expected javax.jms.IllegalStateException, got " + e);
+ }
+ }
+
+ public void testQueueSessionCreateTopic() throws JMSException
+ {
+ try
+ {
+ _queueSession.createTopic("abc");
+ fail("expected exception did not occur");
+ }
+ catch (javax.jms.IllegalStateException s)
+ {
+ // ok
+ }
+ catch (Exception e)
+ {
+ fail("expected javax.jms.IllegalStateException, got " + e);
+ }
+ }
+
+ public void testQueueSessionDurableSubscriber() throws JMSException
+ {
+ try
+ {
+ _queueSession.createDurableSubscriber(_topic, "abc");
+ fail("expected exception did not occur");
+ }
+ catch (javax.jms.IllegalStateException s)
+ {
+ // ok
+ }
+ catch (Exception e)
+ {
+ fail("expected javax.jms.IllegalStateException, got " + e);
+ }
+ }
+
+ public void testQueueSessionUnsubscribe() throws JMSException
+ {
+ try
+ {
+ _queueSession.unsubscribe("abc");
+ fail("expected exception did not occur");
+ }
+ catch (javax.jms.IllegalStateException s)
+ {
+ // ok
+ }
+ catch (Exception e)
+ {
+ fail("expected javax.jms.IllegalStateException, got " + e);
+ }
+ }
+
+ public static junit.framework.Test suite()
+ {
+ return new junit.framework.TestSuite(AMQConnectionTest.class);
+ }
+}
diff --git a/Final/java/client/src/test/java/org/apache/qpid/test/unit/client/AMQSessionTest.java b/Final/java/client/src/test/java/org/apache/qpid/test/unit/client/AMQSessionTest.java
new file mode 100644
index 0000000000..78b7976f55
--- /dev/null
+++ b/Final/java/client/src/test/java/org/apache/qpid/test/unit/client/AMQSessionTest.java
@@ -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.
+ *
+ */
+package org.apache.qpid.test.unit.client;
+
+import javax.jms.JMSException;
+import javax.jms.QueueReceiver;
+import javax.jms.TopicSubscriber;
+
+import junit.framework.TestCase;
+
+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.testutil.VMBrokerSetup;
+
+/**
+ * Tests for QueueReceiver and TopicSubscriber creation methods on AMQSession
+ */
+public class AMQSessionTest extends TestCase
+{
+
+ private static AMQSession _session;
+ private static AMQTopic _topic;
+ private static AMQQueue _queue;
+ private static AMQConnection _connection;
+
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+ _connection = new AMQConnection("vm://:1", "guest", "guest", "fred", "test");
+ _topic = new AMQTopic(_connection,"mytopic");
+ _queue = new AMQQueue(_connection,"myqueue");
+ _session = (AMQSession) _connection.createSession(false, AMQSession.NO_ACKNOWLEDGE);
+ }
+
+ protected void tearDown() throws Exception
+ {
+ try
+ {
+ _connection.close();
+ }
+ catch (JMSException e)
+ {
+ //just close
+ }
+ super.tearDown();
+ }
+
+ public void testCreateSubscriber() throws JMSException
+ {
+ TopicSubscriber subscriber = _session.createSubscriber(_topic);
+ assertEquals("Topic names should match from TopicSubscriber", _topic.getTopicName(), subscriber.getTopic().getTopicName());
+
+ subscriber = _session.createSubscriber(_topic, "abc", false);
+ assertEquals("Topic names should match from TopicSubscriber with selector", _topic.getTopicName(), subscriber.getTopic().getTopicName());
+ }
+
+ public void testCreateDurableSubscriber() throws JMSException
+ {
+ TopicSubscriber subscriber = _session.createDurableSubscriber(_topic, "mysubname");
+ assertEquals("Topic names should match from durable TopicSubscriber", _topic.getTopicName(), subscriber.getTopic().getTopicName());
+
+ subscriber = _session.createDurableSubscriber(_topic, "mysubname", "abc", false);
+ assertEquals("Topic names should match from durable TopicSubscriber with selector", _topic.getTopicName(), subscriber.getTopic().getTopicName());
+ }
+
+ public void testCreateQueueReceiver() throws JMSException
+ {
+ QueueReceiver receiver = _session.createQueueReceiver(_queue);
+ assertEquals("Queue names should match from QueueReceiver", _queue.getQueueName(), receiver.getQueue().getQueueName());
+
+ receiver = _session.createQueueReceiver(_queue, "abc");
+ assertEquals("Queue names should match from QueueReceiver with selector", _queue.getQueueName(), receiver.getQueue().getQueueName());
+ }
+
+ public void testCreateReceiver() throws JMSException
+ {
+ QueueReceiver receiver = _session.createReceiver(_queue);
+ assertEquals("Queue names should match from QueueReceiver", _queue.getQueueName(), receiver.getQueue().getQueueName());
+
+ receiver = _session.createReceiver(_queue, "abc");
+ assertEquals("Queue names should match from QueueReceiver with selector", _queue.getQueueName(), receiver.getQueue().getQueueName());
+ }
+
+ public static void stopVmBrokers()
+ {
+ _queue = null;
+ _topic = null;
+ _session = null;
+ }
+
+ public static junit.framework.Test suite()
+ {
+ return new VMBrokerSetup(new junit.framework.TestSuite(AMQSessionTest.class));
+ }
+}
diff --git a/Final/java/client/src/test/java/org/apache/qpid/test/unit/client/BrokerDetails/BrokerDetailsTest.java b/Final/java/client/src/test/java/org/apache/qpid/test/unit/client/BrokerDetails/BrokerDetailsTest.java
new file mode 100644
index 0000000000..e513f25e3d
--- /dev/null
+++ b/Final/java/client/src/test/java/org/apache/qpid/test/unit/client/BrokerDetails/BrokerDetailsTest.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.test.unit.client.BrokerDetails;
+
+import junit.framework.TestCase;
+
+import org.apache.qpid.client.AMQBrokerDetails;
+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'";
+
+ AMQBrokerDetails broker = new AMQBrokerDetails(url);
+
+ assertTrue(broker.getOption("timeout").equals("200"));
+ assertTrue(broker.getOption("immediatedelivery").equals("true"));
+ }
+
+ public void testVMBroker() throws URLSyntaxException
+ {
+ String url = "vm://:2";
+
+ AMQBrokerDetails broker = new AMQBrokerDetails(url);
+ assertTrue(broker.getTransport().equals("vm"));
+ assertEquals(broker.getPort(), 2);
+ }
+
+ public void testTransportsDefaultToTCP() throws URLSyntaxException
+ {
+ String url = "localhost:5672";
+
+ AMQBrokerDetails broker = new AMQBrokerDetails(url);
+ assertTrue(broker.getTransport().equals("tcp"));
+ }
+
+ public void testCheckDefaultPort() throws URLSyntaxException
+ {
+ String url = "tcp://localhost";
+
+ AMQBrokerDetails broker = new AMQBrokerDetails(url);
+ assertTrue(broker.getPort() == AMQBrokerDetails.DEFAULT_PORT);
+ }
+
+ public void testBothDefaults() throws URLSyntaxException
+ {
+ String url = "localhost";
+
+ AMQBrokerDetails broker = new AMQBrokerDetails(url);
+
+ assertTrue(broker.getTransport().equals("tcp"));
+ assertTrue(broker.getPort() == AMQBrokerDetails.DEFAULT_PORT);
+ }
+
+ public void testWrongOptionSeparatorInBroker()
+ {
+ String url = "tcp://localhost:5672+option='value'";
+ try
+ {
+ new AMQBrokerDetails(url);
+ }
+ catch (URLSyntaxException urise)
+ {
+ assertTrue(urise.getReason().equals("Illegal character in port number"));
+ }
+
+ }
+
+ public static junit.framework.Test suite()
+ {
+ return new junit.framework.TestSuite(BrokerDetailsTest.class);
+ }
+}
diff --git a/Final/java/client/src/test/java/org/apache/qpid/test/unit/client/channelclose/ChannelCloseMethodHandlerNoCloseOk.java b/Final/java/client/src/test/java/org/apache/qpid/test/unit/client/channelclose/ChannelCloseMethodHandlerNoCloseOk.java
new file mode 100644
index 0000000000..575d542633
--- /dev/null
+++ b/Final/java/client/src/test/java/org/apache/qpid/test/unit/client/channelclose/ChannelCloseMethodHandlerNoCloseOk.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.test.unit.client.channelclose;
+
+import org.apache.qpid.AMQChannelClosedException;
+import org.apache.qpid.AMQException;
+import org.apache.qpid.AMQInvalidArgumentException;
+import org.apache.qpid.AMQInvalidRoutingKeyException;
+import org.apache.qpid.client.AMQNoConsumersException;
+import org.apache.qpid.client.AMQNoRouteException;
+import org.apache.qpid.client.protocol.AMQProtocolSession;
+import org.apache.qpid.client.state.AMQStateManager;
+import org.apache.qpid.client.state.StateAwareMethodListener;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.framing.ChannelCloseBody;
+import org.apache.qpid.protocol.AMQConstant;
+import org.apache.qpid.protocol.AMQMethodEvent;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ChannelCloseMethodHandlerNoCloseOk implements StateAwareMethodListener
+{
+ private static final Logger _logger = LoggerFactory.getLogger(ChannelCloseMethodHandlerNoCloseOk.class);
+
+ private static ChannelCloseMethodHandlerNoCloseOk _handler = new ChannelCloseMethodHandlerNoCloseOk();
+
+ public static ChannelCloseMethodHandlerNoCloseOk getInstance()
+ {
+ return _handler;
+ }
+
+ public void methodReceived(AMQStateManager stateManager, AMQProtocolSession protocolSession, AMQMethodEvent evt)
+ throws AMQException
+ {
+ _logger.debug("ChannelClose method received");
+ ChannelCloseBody method = (ChannelCloseBody) evt.getMethod();
+
+ AMQConstant errorCode = AMQConstant.getConstant(method.replyCode);
+ AMQShortString reason = method.replyText;
+ if (_logger.isDebugEnabled())
+ {
+ _logger.debug("Channel close reply code: " + errorCode + ", reason: " + reason);
+ }
+
+ // For this test Method Handler .. don't send Close-OK
+ // // TODO: Be aware of possible changes to parameter order as versions change.
+ // AMQFrame frame = ChannelCloseOkBody.createAMQFrame(evt.getChannelId(), method.getMajor(), method.getMinor());
+ // protocolSession.writeFrame(frame);
+ if (errorCode != AMQConstant.REPLY_SUCCESS)
+ {
+ _logger.error("Channel close received with errorCode " + errorCode + ", and reason " + reason);
+ if (errorCode == AMQConstant.NO_CONSUMERS)
+ {
+ throw new AMQNoConsumersException("Error: " + reason, null);
+ }
+ else if (errorCode == AMQConstant.NO_ROUTE)
+ {
+ throw new AMQNoRouteException("Error: " + reason, null);
+ }
+ else if (errorCode == AMQConstant.INVALID_ARGUMENT)
+ {
+ _logger.debug("Broker responded with Invalid Argument.");
+
+ throw new AMQInvalidArgumentException(String.valueOf(reason));
+ }
+ else if (errorCode == AMQConstant.INVALID_ROUTING_KEY)
+ {
+ _logger.debug("Broker responded with Invalid Routing Key.");
+
+ throw new AMQInvalidRoutingKeyException(String.valueOf(reason));
+ }
+ else
+ {
+ throw new AMQChannelClosedException(errorCode, "Error: " + reason);
+ }
+
+ }
+
+ protocolSession.channelClosed(evt.getChannelId(), errorCode, String.valueOf(reason));
+ }
+}
diff --git a/Final/java/client/src/test/java/org/apache/qpid/test/unit/client/channelclose/ChannelCloseOkTest.java b/Final/java/client/src/test/java/org/apache/qpid/test/unit/client/channelclose/ChannelCloseOkTest.java
new file mode 100644
index 0000000000..559e9a4741
--- /dev/null
+++ b/Final/java/client/src/test/java/org/apache/qpid/test/unit/client/channelclose/ChannelCloseOkTest.java
@@ -0,0 +1,235 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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.channelclose;
+
+import junit.framework.TestCase;
+
+import junit.textui.TestRunner;
+
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.client.AMQQueue;
+import org.apache.qpid.client.transport.TransportConnection;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.jms.Destination;
+import javax.jms.ExceptionListener;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageListener;
+import javax.jms.MessageProducer;
+import javax.jms.Session;
+import javax.jms.TextMessage;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Due to bizarre exception handling all sessions are closed if you get
+ * a channel close request and no exception listener is registered.
+ * <p/>
+ * JIRA issue IBTBLZ-10.
+ * <p/>
+ * Simulate by:
+ * <p/>
+ * 0. Create two sessions with no exception listener.
+ * 1. Publish message to queue/topic that does not exist (wrong routing key).
+ * 2. This will cause a channel close.
+ * 3. Since client does not have an exception listener, currently all sessions are
+ * closed.
+ */
+public class ChannelCloseOkTest extends TestCase
+{
+ private AMQConnection _connection;
+ private Destination _destination1;
+ private Destination _destination2;
+ private Session _session1;
+ private Session _session2;
+ private final List<Message> _received1 = new ArrayList<Message>();
+ 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 = new AMQConnection(_connectionString, "guest", "guest", randomize("Client"), "test");
+
+ _destination1 = new AMQQueue(_connection, "q1", true);
+ _destination2 = new AMQQueue(_connection, "q2", true);
+ _session1 = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ _session1.createConsumer(_destination1).setMessageListener(new MessageListener()
+ {
+ public void onMessage(Message message)
+ {
+ _log.debug("consumer 1 got message [" + getTextMessage(message) + "]");
+ synchronized (_received1)
+ {
+ _received1.add(message);
+ _received1.notify();
+ }
+ }
+ });
+ _session2 = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ _session2.createConsumer(_destination2).setMessageListener(new MessageListener()
+ {
+ public void onMessage(Message message)
+ {
+ _log.debug("consumer 2 got message [" + getTextMessage(message) + "]");
+ synchronized (_received2)
+ {
+ _received2.add(message);
+ _received2.notify();
+ }
+ }
+ });
+
+ _connection.start();
+ }
+
+ private String getTextMessage(Message message)
+ {
+ TextMessage tm = (TextMessage) message;
+ try
+ {
+ return tm.getText();
+ }
+ catch (JMSException e)
+ {
+ return "oops " + e;
+ }
+ }
+
+ protected void tearDown() throws Exception
+ {
+ closeConnection();
+ TransportConnection.killAllVMBrokers();
+ super.tearDown();
+ }
+
+ public void closeConnection() throws JMSException
+ {
+ if (_connection != null)
+ {
+ _log.info(">>>>>>>>>>>>>>.. closing");
+ _connection.close();
+ }
+ }
+
+ public void testWithoutExceptionListener() throws Exception
+ {
+ doTest();
+ }
+
+ public void testWithExceptionListener() throws Exception
+ {
+ _connection.setExceptionListener(new ExceptionListener()
+ {
+ public void onException(JMSException jmsException)
+ {
+ _log.warn("onException - " + jmsException.getMessage());
+ }
+ });
+
+ doTest();
+ }
+
+ public void doTest() throws Exception
+ {
+ // Check both sessions are ok.
+ sendAndWait(_session1, _destination1, "first", _received1, 1);
+ sendAndWait(_session2, _destination2, "second", _received2, 1);
+ assertEquals(1, _received1.size());
+ assertEquals(1, _received2.size());
+
+ // Now send message to incorrect destination on session 1.
+ Destination destination = new AMQQueue(_connection, "incorrect");
+ send(_session1, destination, "third"); // no point waiting as message will never be received.
+
+ // Ensure both sessions are still ok.
+ // Send a bunch of messages as this give time for the sessions to be erroneously closed.
+ final int num = 300;
+ for (int i = 0; i < num; ++i)
+ {
+ send(_session1, _destination1, "" + i);
+ send(_session2, _destination2, "" + i);
+ }
+
+ waitFor(_received1, num + 1);
+ waitFor(_received2, num + 1);
+
+ // Note that the third message is never received as it is sent to an incorrect destination.
+ assertEquals(num + 1, _received1.size());
+ assertEquals(num + 1, _received2.size());
+ }
+
+ private void sendAndWait(Session session, Destination destination, String message, List<Message> received, int count)
+ throws JMSException, InterruptedException
+ {
+ send(session, destination, message);
+ waitFor(received, count);
+ }
+
+ private void send(Session session, Destination destination, String message) throws JMSException
+ {
+ _log.debug("sending message " + message);
+ MessageProducer producer1 = session.createProducer(destination);
+ producer1.send(session.createTextMessage(message));
+ }
+
+ private void waitFor(List<Message> received, int count) throws InterruptedException
+ {
+ synchronized (received)
+ {
+ while (received.size() < count)
+ {
+ try
+ {
+ received.wait();
+ }
+ catch (InterruptedException e)
+ {
+ _log.info("Interrupted: " + e);
+ throw e;
+ }
+ }
+ }
+ }
+
+ private static String randomize(String in)
+ {
+ return in + System.currentTimeMillis();
+ }
+
+ public static void main(String[] args)
+ {
+ TestRunner.run(ChannelCloseOkTest.class);
+ }
+
+ public static junit.framework.Test suite()
+ {
+ return new junit.framework.TestSuite(ChannelCloseOkTest.class);
+ }
+}
diff --git a/Final/java/client/src/test/java/org/apache/qpid/test/unit/client/channelclose/ChannelCloseTest.java b/Final/java/client/src/test/java/org/apache/qpid/test/unit/client/channelclose/ChannelCloseTest.java
new file mode 100644
index 0000000000..f1099ca5ab
--- /dev/null
+++ b/Final/java/client/src/test/java/org/apache/qpid/test/unit/client/channelclose/ChannelCloseTest.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.test.unit.client.channelclose;
+
+import junit.framework.TestCase;
+
+import org.apache.qpid.AMQException;
+import org.apache.qpid.AMQTimeoutException;
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.client.failover.FailoverException;
+import org.apache.qpid.client.failover.FailoverProtectedOperation;
+import org.apache.qpid.client.failover.FailoverRetrySupport;
+import org.apache.qpid.client.protocol.AMQProtocolSession;
+import org.apache.qpid.client.protocol.AMQProtocolHandler;
+import org.apache.qpid.client.state.AMQStateManager;
+import org.apache.qpid.client.transport.TransportConnection;
+import org.apache.qpid.framing.AMQFrame;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.framing.ChannelCloseOkBody;
+import org.apache.qpid.framing.ChannelOpenBody;
+import org.apache.qpid.framing.ChannelOpenOkBody;
+import org.apache.qpid.framing.ExchangeDeclareBody;
+import org.apache.qpid.framing.ExchangeDeclareOkBody;
+import org.apache.qpid.jms.ConnectionListener;
+import org.apache.qpid.protocol.AMQConstant;
+import org.apache.qpid.url.URLSyntaxException;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+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.Queue;
+import javax.jms.Session;
+import javax.jms.TextMessage;
+
+public class ChannelCloseTest extends TestCase implements ExceptionListener, ConnectionListener
+{
+ private static final Logger _logger = LoggerFactory.getLogger(ChannelCloseTest.class);
+
+ Connection _connection;
+ private String _brokerlist = "vm://:1";
+ private Session _session;
+ private static final long SYNC_TIMEOUT = 5000;
+ 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
+ {
+ _connection = newConnection();
+
+ // Create Producer
+ try
+ {
+ _connection.start();
+
+ createChannelAndTest(1);
+
+ // Cause it to close
+ try
+ {
+ _logger.info("Testing invalid exchange");
+ declareExchange(1, "", "name_that_will_lookup_to_null", false);
+ fail("Exchange name is empty so this should fail ");
+ }
+ catch (AMQException e)
+ {
+ assertEquals("Exchange should not be found", AMQConstant.NOT_FOUND, e.getErrorCode());
+ }
+
+ // Check that
+ try
+ {
+ _logger.info("Testing valid exchange should fail");
+ declareExchange(1, "topic", "amq.topic", false);
+ fail("This should not succeed as the channel should be closed ");
+ }
+ catch (AMQException e)
+ {
+ if (_logger.isInfoEnabled())
+ {
+ _logger.info("Exception occured was:" + e.getErrorCode());
+ }
+
+ assertEquals("Connection should be closed", AMQConstant.CHANNEL_ERROR, e.getErrorCode());
+
+ _connection = newConnection();
+ }
+
+ checkSendingMessage();
+
+ _session.close();
+ _connection.close();
+
+ }
+ catch (JMSException e)
+ {
+ e.printStackTrace();
+ fail(e.getMessage());
+ }
+ }
+
+ /*
+ close channel and send guff then send ok no errors
+ */
+ public void testSendingMethodsAfterClose() throws Exception
+ {
+ try
+ {
+ _connection = new AMQConnection("amqp://guest:guest@CCTTest/test?brokerlist='" + _brokerlist + "'");
+
+ ((AMQConnection) _connection).setConnectionListener(this);
+
+ _connection.setExceptionListener(this);
+
+ // Change the StateManager for one that doesn't respond with Close-OKs
+ AMQStateManager oldStateManager = ((AMQConnection) _connection).getProtocolHandler().getStateManager();
+
+ _session = _connection.createSession(false, Session.CLIENT_ACKNOWLEDGE);
+
+ _connection.start();
+
+ // Test connection
+ checkSendingMessage();
+
+ // Set StateManager to manager that ignores Close-oks
+ AMQProtocolSession protocolSession = ((AMQConnection) _connection).getProtocolHandler().getProtocolSession();
+ AMQStateManager newStateManager = new NoCloseOKStateManager(protocolSession);
+ newStateManager.changeState(oldStateManager.getCurrentState());
+
+ ((AMQConnection) _connection).getProtocolHandler().setStateManager(newStateManager);
+
+ final int TEST_CHANNEL = 1;
+ _logger.info("Testing Channel(" + TEST_CHANNEL + ") Creation");
+
+ createChannelAndTest(TEST_CHANNEL);
+
+ // Cause it to close
+ try
+ {
+ _logger.info("Closing Channel - invalid exchange");
+ declareExchange(TEST_CHANNEL, "", "name_that_will_lookup_to_null", false);
+ fail("Exchange name is empty so this should fail ");
+ }
+ catch (AMQException e)
+ {
+ assertEquals("Exchange should not be found", AMQConstant.NOT_FOUND, e.getErrorCode());
+ }
+
+ try
+ {
+ // Send other methods that should be ignored
+ // send them no wait as server will ignore them
+ _logger.info("Tested known exchange - should ignore");
+ declareExchange(TEST_CHANNEL, "topic", "amq.topic", true);
+
+ _logger.info("Tested known invalid exchange - should ignore");
+ declareExchange(TEST_CHANNEL, "", "name_that_will_lookup_to_null", true);
+
+ _logger.info("Tested known invalid exchange - should ignore");
+ declareExchange(TEST_CHANNEL, "", "name_that_will_lookup_to_null", true);
+
+ // Send sync .. server will igore and timy oue
+ _logger.info("Tested known invalid exchange - should ignore");
+ declareExchange(TEST_CHANNEL, "", "name_that_will_lookup_to_null", false);
+ }
+ catch (AMQTimeoutException te)
+ {
+ assertEquals("Request should timeout", AMQConstant.REQUEST_TIMEOUT, te.getErrorCode());
+ }
+ catch (AMQException e)
+ {
+ fail("This should not fail as all requests should be ignored");
+ }
+
+ _logger.info("Sending Close");
+ // Send Close-ok
+ sendClose(TEST_CHANNEL);
+
+ _logger.info("Re-opening channel");
+
+ createChannelAndTest(TEST_CHANNEL);
+
+ // Test connection is still ok
+
+ checkSendingMessage();
+
+ }
+ catch (JMSException e)
+ {
+ e.printStackTrace();
+ fail(e.getMessage());
+ }
+ catch (AMQException e)
+ {
+ fail(e.getMessage());
+
+ }
+ catch (URLSyntaxException e)
+ {
+ fail(e.getMessage());
+ }
+ finally
+ {
+ try
+ {
+ _session.close();
+ _connection.close();
+ }
+ catch (JMSException e)
+ {
+ e.printStackTrace();
+ fail(e.getMessage());
+ }
+ }
+ }
+
+ private void createChannelAndTest(int channel) throws FailoverException
+ {
+ // Create A channel
+ try
+ {
+ createChannel(channel);
+ }
+ catch (AMQException e)
+ {
+ fail(e.getMessage());
+ }
+
+ // Test it is ok
+ try
+ {
+ declareExchange(channel, "topic", "amq.topic", false);
+ _logger.info("Tested known exchange");
+ }
+ catch (AMQException e)
+ {
+ fail("This should not fail as this is the default exchange details");
+ }
+ }
+
+ private void sendClose(int channel)
+ {
+ AMQFrame frame =
+ ChannelCloseOkBody.createAMQFrame(channel,
+ ((AMQConnection) _connection).getProtocolHandler().getProtocolMajorVersion(),
+ ((AMQConnection) _connection).getProtocolHandler().getProtocolMinorVersion());
+
+ ((AMQConnection) _connection).getProtocolHandler().writeFrame(frame);
+ }
+
+ private void checkSendingMessage() throws JMSException
+ {
+ TEST++;
+ _logger.info("Test creating producer which will use channel id 1");
+
+ Queue queue = _session.createTemporaryQueue();
+
+ MessageConsumer consumer = _session.createConsumer(queue);
+
+ MessageProducer producer = _session.createProducer(queue);
+
+ final String MESSAGE = "CCT_Test_Message";
+ producer.send(_session.createTextMessage(MESSAGE));
+
+ Message msg = consumer.receive(2000);
+
+ assertNotNull("Received messages should not be null.", msg);
+ assertEquals("Message received not what we sent", MESSAGE, ((TextMessage) msg).getText());
+ }
+
+ private Connection newConnection()
+ {
+ AMQConnection connection = null;
+ try
+ {
+ connection = new AMQConnection("amqp://guest:guest@CCTTest/test?brokerlist='" + _brokerlist + "'");
+
+ connection.setConnectionListener(this);
+
+ _session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ connection.start();
+
+ }
+ catch (JMSException e)
+ {
+ fail("Creating new connection when:" + e.getMessage());
+ }
+ catch (AMQException e)
+ {
+ fail("Creating new connection when:" + e.getMessage());
+ }
+ catch (URLSyntaxException e)
+ {
+ fail("Creating new connection when:" + e.getMessage());
+ }
+
+ return connection;
+ }
+
+ private void declareExchange(final int channelId, final String _type, final String _name, final boolean nowait)
+ throws AMQException, FailoverException
+ {
+// new FailoverRetrySupport<Object, AMQException>(new FailoverProtectedOperation<Object, AMQException>()
+// {
+// public Object execute() throws AMQException, FailoverException
+// {
+
+ AMQProtocolHandler protocolHandler = ((AMQConnection) _connection).getProtocolHandler();
+
+ AMQFrame exchangeDeclare =
+ ExchangeDeclareBody.createAMQFrame(channelId,
+ protocolHandler.getProtocolMajorVersion(),
+ protocolHandler.getProtocolMinorVersion(), null, // arguments
+ false, // autoDelete
+ false, // durable
+ new AMQShortString(_name), // exchange
+ false, // internal
+ nowait, // nowait
+ true, // passive
+ 0, // ticket
+ new AMQShortString(_type)); // type
+
+ if (nowait)
+ {
+ protocolHandler.writeFrame(exchangeDeclare);
+ }
+ else
+ {
+ protocolHandler.syncWrite(exchangeDeclare, ExchangeDeclareOkBody.class, SYNC_TIMEOUT);
+ }
+
+// return null;
+// }
+// }, (AMQConnection)_connection).execute();
+
+ }
+
+ private void createChannel(int channelId) throws AMQException, FailoverException
+ {
+ ((AMQConnection) _connection).getProtocolHandler().syncWrite(ChannelOpenBody.createAMQFrame(channelId,
+ ((AMQConnection) _connection).getProtocolHandler().getProtocolMajorVersion(),
+ ((AMQConnection) _connection).getProtocolHandler().getProtocolMinorVersion(), null), // outOfBand
+ ChannelOpenOkBody.class);
+
+ }
+
+ public void onException(JMSException jmsException)
+ {
+ // _logger.info("CCT" + jmsException);
+ fail(jmsException.getMessage());
+ }
+
+ public void bytesSent(long count)
+ {
+ }
+
+ public void bytesReceived(long count)
+ {
+ }
+
+ public boolean preFailover(boolean redirect)
+ {
+ return false;
+ }
+
+ public boolean preResubscribe()
+ {
+ return false;
+ }
+
+ public void failoverComplete()
+ {
+ }
+}
diff --git a/Final/java/client/src/test/java/org/apache/qpid/test/unit/client/channelclose/CloseWithBlockingReceiveTest.java b/Final/java/client/src/test/java/org/apache/qpid/test/unit/client/channelclose/CloseWithBlockingReceiveTest.java
new file mode 100644
index 0000000000..9600d1e9d3
--- /dev/null
+++ b/Final/java/client/src/test/java/org/apache/qpid/test/unit/client/channelclose/CloseWithBlockingReceiveTest.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.test.unit.client.channelclose;
+
+import javax.jms.Connection;
+import javax.jms.MessageConsumer;
+import javax.jms.Session;
+
+import junit.framework.TestCase;
+
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.client.AMQTopic;
+import org.apache.qpid.client.transport.TransportConnection;
+
+/**
+ * @author Apache Software Foundation
+ */
+public class CloseWithBlockingReceiveTest extends TestCase
+{
+
+
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+ TransportConnection.createVMBroker(1);
+ }
+
+ protected void tearDown() throws Exception
+ {
+ super.tearDown();
+ TransportConnection.killAllVMBrokers();
+ }
+
+
+ public void testReceiveReturnsNull() throws Exception
+ {
+ final AMQConnection connection = new AMQConnection("vm://:1", "guest", "guest",
+ "fred", "test");
+ Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ MessageConsumer consumer = session.createConsumer(new AMQTopic(connection, "banana"));
+ connection.start();
+
+ Runnable r = new Runnable()
+ {
+
+ public void run()
+ {
+ try
+ {
+ Thread.sleep(1000);
+ connection.close();
+ }
+ catch (Exception e)
+ {
+ }
+ }
+ };
+ long startTime = System.currentTimeMillis();
+ new Thread(r).start();
+ consumer.receive(10000);
+ assertTrue(System.currentTimeMillis() - startTime < 10000);
+ }
+
+ public static junit.framework.Test suite()
+ {
+ return new junit.framework.TestSuite(CloseWithBlockingReceiveTest.class);
+ }
+
+}
diff --git a/Final/java/client/src/test/java/org/apache/qpid/test/unit/client/channelclose/NoCloseOKStateManager.java b/Final/java/client/src/test/java/org/apache/qpid/test/unit/client/channelclose/NoCloseOKStateManager.java
new file mode 100644
index 0000000000..d128f30727
--- /dev/null
+++ b/Final/java/client/src/test/java/org/apache/qpid/test/unit/client/channelclose/NoCloseOKStateManager.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.test.unit.client.channelclose;
+
+import org.apache.qpid.client.state.AMQStateManager;
+import org.apache.qpid.client.state.AMQState;
+import org.apache.qpid.client.handler.ConnectionStartMethodHandler;
+import org.apache.qpid.client.handler.ConnectionCloseMethodHandler;
+import org.apache.qpid.client.handler.ConnectionTuneMethodHandler;
+import org.apache.qpid.client.handler.ConnectionSecureMethodHandler;
+import org.apache.qpid.client.handler.ConnectionOpenOkMethodHandler;
+import org.apache.qpid.client.handler.ChannelCloseOkMethodHandler;
+import org.apache.qpid.client.handler.BasicDeliverMethodHandler;
+import org.apache.qpid.client.handler.BasicReturnMethodHandler;
+import org.apache.qpid.client.handler.BasicCancelOkMethodHandler;
+import org.apache.qpid.client.handler.ChannelFlowOkMethodHandler;
+import org.apache.qpid.client.handler.QueueDeleteOkMethodHandler;
+import org.apache.qpid.client.handler.ExchangeBoundOkMethodHandler;
+import org.apache.qpid.client.protocol.AMQProtocolSession;
+import org.apache.qpid.framing.ConnectionStartBody;
+import org.apache.qpid.framing.ConnectionCloseBody;
+import org.apache.qpid.framing.ConnectionTuneBody;
+import org.apache.qpid.framing.ConnectionSecureBody;
+import org.apache.qpid.framing.ConnectionOpenOkBody;
+import org.apache.qpid.framing.ChannelCloseBody;
+import org.apache.qpid.framing.ChannelCloseOkBody;
+import org.apache.qpid.framing.BasicDeliverBody;
+import org.apache.qpid.framing.BasicReturnBody;
+import org.apache.qpid.framing.BasicCancelOkBody;
+import org.apache.qpid.framing.ChannelFlowOkBody;
+import org.apache.qpid.framing.QueueDeleteOkBody;
+import org.apache.qpid.framing.ExchangeBoundOkBody;
+
+import java.util.Map;
+import java.util.HashMap;
+
+public class NoCloseOKStateManager extends AMQStateManager
+{
+ public NoCloseOKStateManager(AMQProtocolSession protocolSession)
+ {
+ super(protocolSession);
+ }
+
+ protected void registerListeners()
+ {
+ Map frame2handlerMap = new HashMap();
+
+ // we need to register a map for the null (i.e. all state) handlers otherwise you get
+ // a stack overflow in the handler searching code when you present it with a frame for which
+ // no handlers are registered
+ //
+ _state2HandlersMap.put(null, frame2handlerMap);
+
+ frame2handlerMap = new HashMap();
+ frame2handlerMap.put(ConnectionStartBody.class, ConnectionStartMethodHandler.getInstance());
+ frame2handlerMap.put(ConnectionCloseBody.class, ConnectionCloseMethodHandler.getInstance());
+ _state2HandlersMap.put(AMQState.CONNECTION_NOT_STARTED, frame2handlerMap);
+
+ frame2handlerMap = new HashMap();
+ frame2handlerMap.put(ConnectionTuneBody.class, ConnectionTuneMethodHandler.getInstance());
+ frame2handlerMap.put(ConnectionSecureBody.class, ConnectionSecureMethodHandler.getInstance());
+ frame2handlerMap.put(ConnectionCloseBody.class, ConnectionCloseMethodHandler.getInstance());
+ _state2HandlersMap.put(AMQState.CONNECTION_NOT_TUNED, frame2handlerMap);
+
+ frame2handlerMap = new HashMap();
+ frame2handlerMap.put(ConnectionOpenOkBody.class, ConnectionOpenOkMethodHandler.getInstance());
+ frame2handlerMap.put(ConnectionCloseBody.class, ConnectionCloseMethodHandler.getInstance());
+ _state2HandlersMap.put(AMQState.CONNECTION_NOT_OPENED, frame2handlerMap);
+
+ //
+ // ConnectionOpen handlers
+ //
+ frame2handlerMap = new HashMap();
+ // Use Test Handler for Close methods to not send Close-OKs
+ frame2handlerMap.put(ChannelCloseBody.class, ChannelCloseMethodHandlerNoCloseOk.getInstance());
+
+ frame2handlerMap.put(ChannelCloseOkBody.class, ChannelCloseOkMethodHandler.getInstance());
+ frame2handlerMap.put(ConnectionCloseBody.class, ConnectionCloseMethodHandler.getInstance());
+ frame2handlerMap.put(BasicDeliverBody.class, BasicDeliverMethodHandler.getInstance());
+ frame2handlerMap.put(BasicReturnBody.class, BasicReturnMethodHandler.getInstance());
+ frame2handlerMap.put(BasicCancelOkBody.class, BasicCancelOkMethodHandler.getInstance());
+ frame2handlerMap.put(ChannelFlowOkBody.class, ChannelFlowOkMethodHandler.getInstance());
+ frame2handlerMap.put(QueueDeleteOkBody.class, QueueDeleteOkMethodHandler.getInstance());
+ frame2handlerMap.put(ExchangeBoundOkBody.class, ExchangeBoundOkMethodHandler.getInstance());
+ _state2HandlersMap.put(AMQState.CONNECTION_OPEN, frame2handlerMap);
+ }
+
+
+}
diff --git a/Final/java/client/src/test/java/org/apache/qpid/test/unit/client/connection/ConnectionStartTest.java b/Final/java/client/src/test/java/org/apache/qpid/test/unit/client/connection/ConnectionStartTest.java
new file mode 100644
index 0000000000..1d108b9c5c
--- /dev/null
+++ b/Final/java/client/src/test/java/org/apache/qpid/test/unit/client/connection/ConnectionStartTest.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.test.unit.client.connection;
+
+import junit.framework.TestCase;
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.client.AMQQueue;
+import org.apache.qpid.client.AMQSession;
+import org.apache.qpid.client.transport.TransportConnection;
+
+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;
+import javax.jms.Queue;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * ConnectionStartTest:
+ * This test verifies that a fresh connection is not started and no messages are delivered until the connection is
+ * started.
+ *
+ * After the connection is started then the message should be there, and the connection started.
+ *
+ * This Test verifies that using receive() and a messageListener does not cause message delivery before start is called.
+ *
+ */
+public class ConnectionStartTest extends TestCase
+{
+
+ String _broker = "vm://:1";
+
+ AMQConnection _connection;
+ private Session _consumerSess;
+ private MessageConsumer _consumer;
+
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+ TransportConnection.createVMBroker(1);
+
+ try
+ {
+ // Create Consumer Connection
+ _connection = new AMQConnection(_broker, "guest", "guest", "fred", "test");
+
+ _consumerSess = _connection.createSession(false, AMQSession.AUTO_ACKNOWLEDGE);
+
+ Queue queue = _consumerSess.createQueue("ConnectionStartTest");
+
+ _consumer = _consumerSess.createConsumer(queue);
+
+
+ // Create Producer Connection to send message
+ AMQConnection pubCon = new AMQConnection(_broker, "guest", "guest", "fred", "test");
+
+ Session pubSess = pubCon.createSession(false, AMQSession.AUTO_ACKNOWLEDGE);
+
+ MessageProducer pub = pubSess.createProducer(queue);
+
+ pub.send(pubSess.createTextMessage("Initial Message"));
+
+ pubCon.close();
+
+ }
+ catch (Exception e)
+ {
+ fail("Connection to " + _broker + " should succeed. Reason: " + e);
+ }
+ }
+
+ protected void tearDown() throws Exception
+ {
+ _connection.close();
+ TransportConnection.killVMBroker(1);
+ super.tearDown();
+ }
+
+ public void testSimpleReceiveConnection()
+ {
+ try
+ {
+ assertTrue("Connection should not be started", !_connection.started());
+ //Note that this next line will start the dispatcher in the session
+ // should really not be called before _connection start
+ assertNull("There should not be messages waiting for the consumer", _consumer.receiveNoWait());
+ _connection.start();
+ assertNotNull("There should be messages waiting for the consumer", _consumer.receive(1000));
+ assertTrue("Connection should be started", _connection.started());
+
+ }
+ catch (JMSException e)
+ {
+ fail("An error occured during test because:" + e);
+ }
+
+ }
+
+ public void testMessageListenerConnection()
+ {
+ final CountDownLatch _gotMessage = new CountDownLatch(1);
+
+ try
+ {
+ assertTrue("Connection should not be started", !_connection.started());
+ _consumerSess.setMessageListener(new MessageListener()
+ {
+ public void onMessage(Message message)
+ {
+ try
+ {
+ assertTrue("Connection should be started", _connection.started());
+ assertEquals("Mesage Received", "Initial Message", ((TextMessage) message).getText());
+ _gotMessage.countDown();
+ }
+ catch (JMSException e)
+ {
+ fail("Couldn't get message text because:" + e.getCause());
+ }
+ }
+ });
+
+ // Ensure that setting a ML doesn't start the connection
+ assertTrue("Connection should not be started", !_connection.started());
+ // Ensure that the message wasn't delivered while the connection was stopped.
+ assertEquals("Message latch should still be set",1,_gotMessage.getCount());
+
+ _connection.start();
+ assertTrue("Connection should be started", _connection.started());
+
+ try
+ {
+ _gotMessage.await(1000, TimeUnit.MILLISECONDS);
+ }
+ catch (InterruptedException e)
+ {
+ fail("Timed out awaiting message via onMessage");
+ }
+
+ }
+ catch (JMSException e)
+ {
+ fail("Failed because:" + e.getCause());
+ }
+
+ }
+
+
+ public static junit.framework.Test suite()
+ {
+ return new junit.framework.TestSuite(ConnectionStartTest.class);
+ }
+}
diff --git a/Final/java/client/src/test/java/org/apache/qpid/test/unit/client/connection/ConnectionTest.java b/Final/java/client/src/test/java/org/apache/qpid/test/unit/client/connection/ConnectionTest.java
new file mode 100644
index 0000000000..56394fee27
--- /dev/null
+++ b/Final/java/client/src/test/java/org/apache/qpid/test/unit/client/connection/ConnectionTest.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.unit.client.connection;
+
+import org.apache.qpid.AMQConnectionFailureException;
+import org.apache.qpid.AMQException;
+import org.apache.qpid.AMQUnresolvedAddressException;
+import org.apache.qpid.client.AMQAuthenticationException;
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.client.AMQQueue;
+import org.apache.qpid.client.AMQTopic;
+import org.apache.qpid.client.transport.TransportConnection;
+import org.apache.qpid.jms.Session;
+
+import junit.framework.TestCase;
+
+import javax.jms.Connection;
+import javax.jms.QueueSession;
+import javax.jms.TopicSession;
+
+public class ConnectionTest extends TestCase
+{
+
+ String _broker = "vm://:1";
+ String _broker_NotRunning = "vm://:2";
+ String _broker_BadDNS = "tcp://hg3sgaaw4lgihjs";
+
+
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+ TransportConnection.createVMBroker(1);
+ }
+
+ protected void tearDown() throws Exception
+ {
+ TransportConnection.killVMBroker(1);
+ }
+
+ public void testSimpleConnection()
+ {
+ try
+ {
+ AMQConnection conn = new AMQConnection(_broker, "guest", "guest", "fred", "test");
+ conn.close();
+ }
+ catch (Exception e)
+ {
+ fail("Connection to " + _broker + " should succeed. Reason: " + e);
+ }
+ }
+
+
+ public void testDefaultExchanges()
+ {
+ try
+ {
+ AMQConnection conn = new AMQConnection("amqp://guest:guest@clientid/test?brokerlist='"
+ + _broker
+ + "?retries='1''&defaultQueueExchange='test.direct'"
+ + "&defaultTopicExchange='test.topic'"
+ + "&temporaryQueueExchange='tmp.direct'"
+ + "&temporaryTopicExchange='tmp.topic'");
+
+ QueueSession queueSession = conn.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ AMQQueue queue = (AMQQueue) queueSession.createQueue("MyQueue");
+
+ assertEquals(queue.getExchangeName().toString(), "test.direct");
+
+ AMQQueue tempQueue = (AMQQueue) queueSession.createTemporaryQueue();
+
+ assertEquals(tempQueue.getExchangeName().toString(), "tmp.direct");
+
+
+ queueSession.close();
+
+
+ TopicSession topicSession = conn.createTopicSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ AMQTopic topic = (AMQTopic) topicSession.createTopic("silly.topic");
+
+ assertEquals(topic.getExchangeName().toString(), "test.topic");
+
+ AMQTopic tempTopic = (AMQTopic) topicSession.createTemporaryTopic();
+
+ assertEquals(tempTopic.getExchangeName().toString(), "tmp.topic");
+
+ topicSession.close();
+
+
+ conn.close();
+ }
+ catch (Exception e)
+ {
+ fail("Connection to " + _broker + " should succeed. Reason: " + e);
+ }
+ }
+
+ //fixme AMQAuthenticationException is not propogaged
+ public void PasswordFailureConnection() throws Exception
+ {
+ try
+ {
+ new AMQConnection("amqp://guest:rubbishpassword@clientid/test?brokerlist='" + _broker + "?retries='1''");
+ fail("Connection should not be established password is wrong.");
+ }
+ catch (AMQException amqe)
+ {
+ if (!(amqe instanceof AMQAuthenticationException))
+ {
+ fail("Correct exception not thrown. Excpected 'AMQAuthenticationException' got: " + amqe);
+ }
+ }
+ }
+
+ public void testConnectionFailure() throws Exception
+ {
+ try
+ {
+ new AMQConnection("amqp://guest:guest@clientid/testpath?brokerlist='" + _broker_NotRunning + "?retries='0''");
+ fail("Connection should not be established");
+ }
+ catch (AMQException amqe)
+ {
+ if (!(amqe instanceof AMQConnectionFailureException))
+ {
+ fail("Correct exception not thrown. Excpected 'AMQConnectionException' got: " + amqe);
+ }
+ }
+
+ }
+
+ public void testUnresolvedHostFailure() throws Exception
+ {
+ try
+ {
+ new AMQConnection("amqp://guest:guest@clientid/testpath?brokerlist='" + _broker_BadDNS + "?retries='0''");
+ fail("Connection should not be established");
+ }
+ catch (AMQException amqe)
+ {
+ if (!(amqe instanceof AMQUnresolvedAddressException))
+ {
+ fail("Correct exception not thrown. Excpected 'AMQUnresolvedAddressException' got: " + amqe);
+ }
+ }
+ }
+
+ public void testClientIdCannotBeChanged() throws Exception
+ {
+ Connection connection = new AMQConnection(_broker, "guest", "guest",
+ "fred", "test");
+ try
+ {
+ connection.setClientID("someClientId");
+ fail("No IllegalStateException thrown when resetting clientid");
+ }
+ catch (javax.jms.IllegalStateException e)
+ {
+ // PASS
+ }
+ }
+
+ public void testClientIdIsPopulatedAutomatically() throws Exception
+ {
+ Connection connection = new AMQConnection(_broker, "guest", "guest",
+ null, "test");
+ assertNotNull(connection.getClientID());
+ }
+
+ public static junit.framework.Test suite()
+ {
+ return new junit.framework.TestSuite(ConnectionTest.class);
+ }
+}
diff --git a/Final/java/client/src/test/java/org/apache/qpid/test/unit/client/connectionurl/ConnectionURLTest.java b/Final/java/client/src/test/java/org/apache/qpid/test/unit/client/connectionurl/ConnectionURLTest.java
new file mode 100644
index 0000000000..bfbba61913
--- /dev/null
+++ b/Final/java/client/src/test/java/org/apache/qpid/test/unit/client/connectionurl/ConnectionURLTest.java
@@ -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.
+ *
+ */
+package org.apache.qpid.test.unit.client.connectionurl;
+
+import junit.framework.TestCase;
+
+import org.apache.qpid.client.AMQBrokerDetails;
+import org.apache.qpid.client.AMQConnectionURL;
+import org.apache.qpid.jms.BrokerDetails;
+import org.apache.qpid.jms.ConnectionURL;
+import org.apache.qpid.url.URLSyntaxException;
+
+public class ConnectionURLTest extends TestCase
+{
+
+ public void testFailoverURL() throws URLSyntaxException
+ {
+ String url = "amqp://ritchiem:bob@/test?brokerlist='tcp://localhost:5672;tcp://fancyserver:3000/',failover='roundrobin'";
+
+ ConnectionURL connectionurl = new AMQConnectionURL(url);
+
+ assertTrue(connectionurl.getFailoverMethod().equals("roundrobin"));
+ assertTrue(connectionurl.getUsername().equals("ritchiem"));
+ assertTrue(connectionurl.getPassword().equals("bob"));
+ assertTrue(connectionurl.getVirtualHost().equals("/test"));
+
+ assertTrue(connectionurl.getBrokerCount() == 2);
+
+ BrokerDetails service = connectionurl.getBrokerDetails(0);
+
+ assertTrue(service.getTransport().equals("tcp"));
+ assertTrue(service.getHost().equals("localhost"));
+ assertTrue(service.getPort() == 5672);
+
+ service = connectionurl.getBrokerDetails(1);
+
+ assertTrue(service.getTransport().equals("tcp"));
+ assertTrue(service.getHost().equals("fancyserver"));
+ assertTrue(service.getPort() == 3000);
+
+ }
+
+ public void testSingleTransportUsernamePasswordURL() throws URLSyntaxException
+ {
+ String url = "amqp://ritchiem:bob@/test?brokerlist='tcp://localhost:5672'";
+
+ ConnectionURL connectionurl = new AMQConnectionURL(url);
+
+ assertTrue(connectionurl.getFailoverMethod() == null);
+ assertTrue(connectionurl.getUsername().equals("ritchiem"));
+ assertTrue(connectionurl.getPassword().equals("bob"));
+ assertTrue(connectionurl.getVirtualHost().equals("/test"));
+
+ assertTrue(connectionurl.getBrokerCount() == 1);
+
+ BrokerDetails service = connectionurl.getBrokerDetails(0);
+
+ assertTrue(service.getTransport().equals("tcp"));
+ assertTrue(service.getHost().equals("localhost"));
+ assertTrue(service.getPort() == 5672);
+ }
+
+ public void testSingleTransportUsernameBlankPasswordURL() throws URLSyntaxException
+ {
+ String url = "amqp://ritchiem:@/test?brokerlist='tcp://localhost:5672'";
+
+ ConnectionURL connectionurl = new AMQConnectionURL(url);
+
+ assertTrue(connectionurl.getFailoverMethod() == null);
+ assertTrue(connectionurl.getUsername().equals("ritchiem"));
+ assertTrue(connectionurl.getPassword().equals(""));
+ assertTrue(connectionurl.getVirtualHost().equals("/test"));
+
+ assertTrue(connectionurl.getBrokerCount() == 1);
+
+ BrokerDetails service = connectionurl.getBrokerDetails(0);
+
+ assertTrue(service.getTransport().equals("tcp"));
+ assertTrue(service.getHost().equals("localhost"));
+ assertTrue(service.getPort() == 5672);
+ }
+
+ public void testFailedURLNullPassword()
+ {
+ String url = "amqp://ritchiem@/test?brokerlist='tcp://localhost:5672'";
+
+ try
+ {
+ new AMQConnectionURL(url);
+ fail("URL has null password");
+ }
+ catch (URLSyntaxException e)
+ {
+ assertTrue(e.getReason().equals("Null password in user information not allowed."));
+ assertTrue(e.getIndex() == 7);
+ }
+ }
+
+
+ public void testSingleTransportURL() throws URLSyntaxException
+ {
+ String url = "amqp://guest:guest@/test?brokerlist='tcp://localhost:5672'";
+
+ ConnectionURL connectionurl = new AMQConnectionURL(url);
+
+
+ assertTrue(connectionurl.getFailoverMethod() == null);
+ assertTrue(connectionurl.getUsername().equals("guest"));
+ assertTrue(connectionurl.getPassword().equals("guest"));
+ assertTrue(connectionurl.getVirtualHost().equals("/test"));
+
+
+ assertTrue(connectionurl.getBrokerCount() == 1);
+
+
+ BrokerDetails service = connectionurl.getBrokerDetails(0);
+
+ assertTrue(service.getTransport().equals("tcp"));
+ assertTrue(service.getHost().equals("localhost"));
+ assertTrue(service.getPort() == 5672);
+ }
+
+ public void testSingleTransportWithClientURLURL() throws URLSyntaxException
+ {
+ String url = "amqp://guest:guest@clientname/test?brokerlist='tcp://localhost:5672'";
+
+ ConnectionURL connectionurl = new AMQConnectionURL(url);
+
+
+ assertTrue(connectionurl.getFailoverMethod() == null);
+ assertTrue(connectionurl.getUsername().equals("guest"));
+ assertTrue(connectionurl.getPassword().equals("guest"));
+ assertTrue(connectionurl.getVirtualHost().equals("/test"));
+ assertTrue(connectionurl.getClientName().equals("clientname"));
+
+
+ assertTrue(connectionurl.getBrokerCount() == 1);
+
+
+ BrokerDetails service = connectionurl.getBrokerDetails(0);
+
+ assertTrue(service.getTransport().equals("tcp"));
+ assertTrue(service.getHost().equals("localhost"));
+ assertTrue(service.getPort() == 5672);
+ }
+
+ public void testSingleTransport1OptionURL() throws URLSyntaxException
+ {
+ String url = "amqp://guest:guest@/test?brokerlist='tcp://localhost:5672',routingkey='jim'";
+
+ ConnectionURL connectionurl = new AMQConnectionURL(url);
+
+ assertTrue(connectionurl.getFailoverMethod() == null);
+ assertTrue(connectionurl.getUsername().equals("guest"));
+ assertTrue(connectionurl.getPassword().equals("guest"));
+ assertTrue(connectionurl.getVirtualHost().equals("/test"));
+
+
+ assertTrue(connectionurl.getBrokerCount() == 1);
+
+ BrokerDetails service = connectionurl.getBrokerDetails(0);
+
+ assertTrue(service.getTransport().equals("tcp"));
+
+ assertTrue(service.getHost().equals("localhost"));
+ assertTrue(service.getPort() == 5672);
+ assertTrue(connectionurl.getOption("routingkey").equals("jim"));
+ }
+
+ public void testSingleTransportDefaultedBroker() throws URLSyntaxException
+ {
+ String url = "amqp://guest:guest@/test?brokerlist='localhost'";
+
+ ConnectionURL connectionurl = new AMQConnectionURL(url);
+
+ assertTrue(connectionurl.getFailoverMethod() == null);
+ assertTrue(connectionurl.getUsername().equals("guest"));
+ assertTrue(connectionurl.getPassword().equals("guest"));
+ assertTrue(connectionurl.getVirtualHost().equals("/test"));
+
+
+ assertTrue(connectionurl.getBrokerCount() == 1);
+
+ BrokerDetails service = connectionurl.getBrokerDetails(0);
+
+ assertTrue(service.getTransport().equals("tcp"));
+
+ assertTrue(service.getHost().equals("localhost"));
+ assertTrue(service.getPort() == 5672);
+ }
+
+ public void testSingleTransportDefaultedBrokerWithPort() throws URLSyntaxException
+ {
+ String url = "amqp://guest:guest@/test?brokerlist='localhost:1234'";
+
+ ConnectionURL connectionurl = new AMQConnectionURL(url);
+
+ assertTrue(connectionurl.getFailoverMethod() == null);
+ assertTrue(connectionurl.getUsername().equals("guest"));
+ assertTrue(connectionurl.getPassword().equals("guest"));
+ assertTrue(connectionurl.getVirtualHost().equals("/test"));
+
+
+ assertTrue(connectionurl.getBrokerCount() == 1);
+
+ BrokerDetails service = connectionurl.getBrokerDetails(0);
+
+ assertTrue(service.getTransport().equals("tcp"));
+
+ assertTrue(service.getHost().equals("localhost"));
+ assertTrue(service.getPort() == 1234);
+ }
+
+ public void testSingleTransportDefaultedBrokerWithIP() throws URLSyntaxException
+ {
+ String url = "amqp://guest:guest@/test?brokerlist='127.0.0.1'";
+
+ ConnectionURL connectionurl = new AMQConnectionURL(url);
+
+ assertTrue(connectionurl.getFailoverMethod() == null);
+ assertTrue(connectionurl.getUsername().equals("guest"));
+ assertTrue(connectionurl.getPassword().equals("guest"));
+ assertTrue(connectionurl.getVirtualHost().equals("/test"));
+
+
+ assertTrue(connectionurl.getBrokerCount() == 1);
+
+ BrokerDetails service = connectionurl.getBrokerDetails(0);
+
+ assertTrue(service.getTransport().equals("tcp"));
+
+ assertTrue(service.getHost().equals("127.0.0.1"));
+ assertTrue(service.getPort() == 5672);
+ }
+
+ public void testSingleTransportDefaultedBrokerWithIPandPort() throws URLSyntaxException
+ {
+ String url = "amqp://guest:guest@/test?brokerlist='127.0.0.1:1234'";
+
+// ConnectionURL connectionurl = new AMQConnectionURL(url);
+//
+// assertTrue(connectionurl.getFailoverMethod() == null);
+// assertTrue(connectionurl.getUsername().equals("guest"));
+// assertTrue(connectionurl.getPassword().equals("guest"));
+// assertTrue(connectionurl.getVirtualHost().equals("/temp"));
+//
+//
+// assertTrue(connectionurl.getBrokerCount() == 1);
+//
+// BrokerDetails service = connectionurl.getBrokerDetails(0);
+//
+// assertTrue(service.getTransport().equals("tcp"));
+//
+// assertTrue(service.getHost().equals("127.0.0.1"));
+// assertTrue(service.getPort() == 1234);
+ }
+
+
+ public void testSingleTransportMultiOptionURL() throws URLSyntaxException
+ {
+ String url = "amqp://guest:guest@/test?brokerlist='tcp://localhost:5672',routingkey='jim',timeout='200',immediatedelivery='true'";
+
+ ConnectionURL connectionurl = new AMQConnectionURL(url);
+
+ assertTrue(connectionurl.getFailoverMethod() == null);
+ assertTrue(connectionurl.getUsername().equals("guest"));
+ assertTrue(connectionurl.getPassword().equals("guest"));
+ assertTrue(connectionurl.getVirtualHost().equals("/test"));
+
+ assertTrue(connectionurl.getBrokerCount() == 1);
+
+ BrokerDetails service = connectionurl.getBrokerDetails(0);
+
+ assertTrue(service.getTransport().equals("tcp"));
+
+ assertTrue(service.getHost().equals("localhost"));
+ assertTrue(service.getPort() == 5672);
+
+ assertTrue(connectionurl.getOption("routingkey").equals("jim"));
+ assertTrue(connectionurl.getOption("timeout").equals("200"));
+ assertTrue(connectionurl.getOption("immediatedelivery").equals("true"));
+ }
+
+ public void testSinglevmURL() throws URLSyntaxException
+ {
+ String url = "amqp://guest:guest@/test?brokerlist='vm://:2'";
+
+ ConnectionURL connectionurl = new AMQConnectionURL(url);
+
+ assertTrue(connectionurl.getFailoverMethod() == null);
+ assertTrue(connectionurl.getUsername().equals("guest"));
+ assertTrue(connectionurl.getPassword().equals("guest"));
+ assertTrue(connectionurl.getVirtualHost().equals("/test"));
+
+ assertTrue(connectionurl.getBrokerCount() == 1);
+
+ BrokerDetails service = connectionurl.getBrokerDetails(0);
+
+ assertTrue(service.getTransport().equals("vm"));
+ assertTrue(service.getHost().equals(""));
+ assertTrue(service.getPort() == 2);
+
+ }
+
+ public void testFailoverVMURL() throws URLSyntaxException
+ {
+ String url = "amqp://ritchiem:bob@/test?brokerlist='vm://:2;vm://:3',failover='roundrobin'";
+
+ ConnectionURL connectionurl = new AMQConnectionURL(url);
+
+ assertTrue(connectionurl.getFailoverMethod().equals("roundrobin"));
+ assertTrue(connectionurl.getUsername().equals("ritchiem"));
+ assertTrue(connectionurl.getPassword().equals("bob"));
+ assertTrue(connectionurl.getVirtualHost().equals("/test"));
+
+ assertTrue(connectionurl.getBrokerCount() == 2);
+
+ BrokerDetails service = connectionurl.getBrokerDetails(0);
+
+ assertTrue(service.getTransport().equals("vm"));
+ assertTrue(service.getHost().equals(""));
+ assertTrue(service.getPort() == 2);
+
+ service = connectionurl.getBrokerDetails(1);
+ assertTrue(service.getTransport().equals("vm"));
+ assertTrue(service.getHost().equals(""));
+ assertTrue(service.getPort() == 3);
+ }
+
+
+ public void testNoVirtualHostURL()
+ {
+ String url = "amqp://user@?brokerlist='tcp://localhost:5672'";
+
+ try
+ {
+ new AMQConnectionURL(url);
+ fail("URL has no virtual host should not parse");
+ }
+ catch (URLSyntaxException e)
+ {
+ // This should occur.
+ }
+ }
+
+ public void testNoClientID() throws URLSyntaxException
+ {
+ String url = "amqp://user:@/test?brokerlist='tcp://localhost:5672'";
+
+ ConnectionURL connectionurl = new AMQConnectionURL(url);
+
+ assertTrue(connectionurl.getUsername().equals("user"));
+ assertTrue(connectionurl.getPassword().equals(""));
+ assertTrue(connectionurl.getVirtualHost().equals("/test"));
+
+ assertTrue(connectionurl.getBrokerCount() == 1);
+ }
+
+
+ public void testWrongOptionSeparatorInOptions()
+ {
+ String url = "amqp://guest:guest@/test?brokerlist='tcp://localhost:5672;tcp://localhost:5673'+failover='roundrobin'";
+ try
+ {
+ new AMQConnectionURL(url);
+ fail("URL Should not parse");
+ }
+ catch (URLSyntaxException urise)
+ {
+ assertTrue(urise.getReason().equals("Unterminated option. Possible illegal option separator:'+'"));
+ }
+
+ }
+
+
+ public void testNoUserDetailsProvidedWithClientID()
+
+ {
+ String url = "amqp://clientID/test?brokerlist='tcp://localhost:5672;tcp://localhost:5673'";
+ try
+ {
+ new AMQConnectionURL(url);
+ fail("URL Should not parse");
+ }
+ catch (URLSyntaxException urise)
+ {
+ assertTrue(urise.getMessage().startsWith("User information not found on url"));
+ }
+
+ }
+
+ public void testNoUserDetailsProvidedNOClientID()
+
+ {
+ String url = "amqp:///test?brokerlist='tcp://localhost:5672;tcp://localhost:5673'";
+ try
+ {
+ new AMQConnectionURL(url);
+ fail("URL Should not parse");
+ }
+ catch (URLSyntaxException urise)
+ {
+ assertTrue(urise.getMessage().startsWith("User information not found on url"));
+ }
+
+ }
+
+ public void testCheckVirtualhostFormat() throws URLSyntaxException
+ {
+ String url = "amqp://guest:guest@/t.-_+!=:?brokerlist='tcp://localhost:5672'";
+
+ AMQConnectionURL connection = new AMQConnectionURL(url);
+ assertTrue(connection.getVirtualHost().equals("/t.-_+!=:"));
+ }
+
+ public void testCheckDefaultPort() throws URLSyntaxException
+ {
+ String url = "amqp://guest:guest@/test=:?brokerlist='tcp://localhost'";
+
+ AMQConnectionURL connection = new AMQConnectionURL(url);
+
+ BrokerDetails broker = connection.getBrokerDetails(0);
+ assertTrue(broker.getPort() == AMQBrokerDetails.DEFAULT_PORT);
+
+ }
+
+ public void testCheckMissingFinalQuote() throws URLSyntaxException
+ {
+ String url = "amqp://guest:guest@id/test" + "?brokerlist='tcp://localhost:5672";
+
+ try
+ {
+ new AMQConnectionURL(url);
+ }
+ catch (URLSyntaxException e)
+ {
+ assertEquals(e.getMessage(), "Unterminated option at index 32: brokerlist='tcp://localhost:5672");
+ }
+ }
+
+
+ public void testDefaultExchanges() throws URLSyntaxException
+ {
+ String url = "amqp://guest:guest@id/test" + "?defaultQueueExchange='test.direct'&defaultTopicExchange='test.topic'&temporaryQueueExchange='tmp.direct'&temporaryTopicExchange='tmp.topic'";
+
+ AMQConnectionURL conn = new AMQConnectionURL(url);
+
+ assertEquals(conn.getDefaultQueueExchangeName(),"test.direct");
+
+ assertEquals(conn.getDefaultTopicExchangeName(),"test.topic");
+
+ assertEquals(conn.getTemporaryQueueExchangeName(),"tmp.direct");
+
+ assertEquals(conn.getTemporaryTopicExchangeName(),"tmp.topic");
+
+ }
+
+
+ public static junit.framework.Test suite()
+ {
+ return new junit.framework.TestSuite(ConnectionURLTest.class);
+ }
+}
diff --git a/Final/java/client/src/test/java/org/apache/qpid/test/unit/client/destinationurl/DestinationURLTest.java b/Final/java/client/src/test/java/org/apache/qpid/test/unit/client/destinationurl/DestinationURLTest.java
new file mode 100644
index 0000000000..66be1ebc73
--- /dev/null
+++ b/Final/java/client/src/test/java/org/apache/qpid/test/unit/client/destinationurl/DestinationURLTest.java
@@ -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.
+ *
+ */
+package org.apache.qpid.test.unit.client.destinationurl;
+
+import junit.framework.TestCase;
+
+import org.apache.qpid.exchange.ExchangeDefaults;
+import org.apache.qpid.url.AMQBindingURL;
+import org.apache.qpid.url.URLSyntaxException;
+
+public class DestinationURLTest extends TestCase
+{
+ public void testFullURL() throws URLSyntaxException
+ {
+
+ String url = "exchange.Class://exchangeName/Destination/Queue";
+
+ AMQBindingURL dest = new AMQBindingURL(url);
+
+ assertTrue(url.equals(dest.toString()));
+
+ assertTrue(dest.getExchangeClass().equals("exchange.Class"));
+ assertTrue(dest.getExchangeName().equals("exchangeName"));
+ assertTrue(dest.getDestinationName().equals("Destination"));
+ assertTrue(dest.getQueueName().equals("Queue"));
+ }
+
+ public void testQueue() throws URLSyntaxException
+ {
+
+ String url = "exchangeClass://exchangeName//Queue";
+
+ AMQBindingURL dest = new AMQBindingURL(url);
+
+ assertTrue(url.equals(dest.toString()));
+
+ assertTrue(dest.getExchangeClass().equals("exchangeClass"));
+ assertTrue(dest.getExchangeName().equals("exchangeName"));
+ assertTrue(dest.getDestinationName().equals(""));
+ assertTrue(dest.getQueueName().equals("Queue"));
+ }
+
+ public void testQueueWithOption() throws URLSyntaxException
+ {
+
+ String url = "exchangeClass://exchangeName//Queue?option='value'";
+
+ AMQBindingURL dest = new AMQBindingURL(url);
+
+ assertTrue(url.equals(dest.toString()));
+
+ assertTrue(dest.getExchangeClass().equals("exchangeClass"));
+ assertTrue(dest.getExchangeName().equals("exchangeName"));
+ assertTrue(dest.getDestinationName().equals(""));
+ assertTrue(dest.getQueueName().equals("Queue"));
+ assertTrue(dest.getOption("option").equals("value"));
+ }
+
+
+ public void testDestination() throws URLSyntaxException
+ {
+
+ String url = "exchangeClass://exchangeName/Destination/";
+
+ AMQBindingURL dest = new AMQBindingURL(url);
+
+ assertTrue(url.equals(dest.toString()));
+
+ assertTrue(dest.getExchangeClass().equals("exchangeClass"));
+ assertTrue(dest.getExchangeName().equals("exchangeName"));
+ assertTrue(dest.getDestinationName().equals("Destination"));
+ assertTrue(dest.getQueueName().equals(""));
+ }
+
+ public void testDestinationWithOption() throws URLSyntaxException
+ {
+
+ String url = "exchangeClass://exchangeName/Destination/?option='value'";
+
+ AMQBindingURL dest = new AMQBindingURL(url);
+
+ assertTrue(url.equals(dest.toString()));
+
+ assertTrue(dest.getExchangeClass().equals("exchangeClass"));
+ assertTrue(dest.getExchangeName().equals("exchangeName"));
+ assertTrue(dest.getDestinationName().equals("Destination"));
+ assertTrue(dest.getQueueName().equals(""));
+
+ assertTrue(dest.getOption("option").equals("value"));
+ }
+
+ public void testDestinationWithMultiOption() throws URLSyntaxException
+ {
+
+ String url = "exchangeClass://exchangeName/Destination/?option='value',option2='value2'";
+
+ AMQBindingURL dest = new AMQBindingURL(url);
+
+ assertTrue(dest.getExchangeClass().equals("exchangeClass"));
+ assertTrue(dest.getExchangeName().equals("exchangeName"));
+ assertTrue(dest.getDestinationName().equals("Destination"));
+ assertTrue(dest.getQueueName().equals(""));
+
+ assertTrue(dest.getOption("option").equals("value"));
+ assertTrue(dest.getOption("option2").equals("value2"));
+ }
+
+ public void testDestinationWithNoExchangeDefaultsToDirect() throws URLSyntaxException
+ {
+
+ String url = "IBMPerfQueue1?durable='true'";
+
+ AMQBindingURL dest = new AMQBindingURL(url);
+
+ assertTrue(dest.getExchangeClass().equals(ExchangeDefaults.DIRECT_EXCHANGE_CLASS));
+ assertTrue(dest.getExchangeName().equals(""));
+ assertTrue(dest.getDestinationName().equals(""));
+ assertTrue(dest.getQueueName().equals("IBMPerfQueue1"));
+
+ assertTrue(dest.getOption("durable").equals("true"));
+ }
+
+ public static junit.framework.Test suite()
+ {
+ return new junit.framework.TestSuite(DestinationURLTest.class);
+ }
+}
diff --git a/Final/java/client/src/test/java/org/apache/qpid/test/unit/client/forwardall/Client.java b/Final/java/client/src/test/java/org/apache/qpid/test/unit/client/forwardall/Client.java
new file mode 100644
index 0000000000..19ef612bcc
--- /dev/null
+++ b/Final/java/client/src/test/java/org/apache/qpid/test/unit/client/forwardall/Client.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.test.unit.client.forwardall;
+
+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.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.jms.Message;
+import javax.jms.MessageListener;
+
+/**
+ * Declare a private temporary response queue,
+ * send a message to amq.direct with a well known routing key with the
+ * private response queue as the reply-to destination
+ * consume responses.
+ */
+public class Client implements MessageListener
+{
+ private static final Logger _logger = LoggerFactory.getLogger(Client.class);
+
+ private final AMQConnection _connection;
+ private final AMQSession _session;
+ private final int _expected;
+ private int _count;
+
+ Client(String broker, int expected) throws Exception
+ {
+ this(connect(broker), expected);
+ }
+
+ Client(AMQConnection connection, int expected) throws Exception
+ {
+ _connection = connection;
+ _expected = expected;
+ _session = (AMQSession) _connection.createSession(false, AMQSession.NO_ACKNOWLEDGE);
+ AMQQueue response =
+ new AMQQueue(_connection.getDefaultQueueExchangeName(), new AMQShortString("ResponseQueue"), true);
+ _session.createConsumer(response).setMessageListener(this);
+ _connection.start();
+ AMQQueue service = new SpecialQueue(_connection, "ServiceQueue");
+ Message request = _session.createTextMessage("Request!");
+ request.setJMSReplyTo(response);
+ _session.createProducer(service).send(request);
+ }
+
+ void shutdownWhenComplete() throws Exception
+ {
+ waitUntilComplete();
+ _connection.close();
+ }
+
+ public synchronized void onMessage(Message response)
+ {
+
+ _logger.info("Received " + (++_count) + " of " + _expected + " responses.");
+ if (_count == _expected)
+ {
+
+ notifyAll();
+ }
+
+ }
+
+ synchronized void waitUntilComplete() throws Exception
+ {
+
+ if (_count < _expected)
+ {
+ wait(10000L);
+ }
+
+ if (_count < _expected)
+ {
+ throw new Exception("Didn't receive all messages... got " + _count + " expected " + _expected);
+ }
+ }
+
+ static AMQConnection connect(String broker) throws Exception
+ {
+ return new AMQConnection(broker, "guest", "guest", "Client" + System.currentTimeMillis(), "test");
+ }
+
+ public static void main(String[] argv) throws Exception
+ {
+ final String connectionString;
+ final int expected;
+ if (argv.length == 0)
+ {
+ connectionString = "localhost:5672";
+ expected = 100;
+ }
+ else
+ {
+ connectionString = argv[0];
+ expected = Integer.parseInt(argv[1]);
+ }
+
+ new Client(connect(connectionString), expected).shutdownWhenComplete();
+ }
+}
diff --git a/Final/java/client/src/test/java/org/apache/qpid/test/unit/client/forwardall/CombinedTest.java b/Final/java/client/src/test/java/org/apache/qpid/test/unit/client/forwardall/CombinedTest.java
new file mode 100644
index 0000000000..9cde24dd92
--- /dev/null
+++ b/Final/java/client/src/test/java/org/apache/qpid/test/unit/client/forwardall/CombinedTest.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.test.unit.client.forwardall;
+
+import junit.framework.TestCase;
+import org.apache.qpid.testutil.VMBrokerSetup;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Runs the Service's and Client parts of the test in the same process
+ * as the broker
+ */
+public class CombinedTest extends TestCase
+{
+ private static final Logger _logger = LoggerFactory.getLogger(CombinedTest.class);
+ private int run = 0;
+
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+ }
+
+ protected void tearDown() throws Exception
+ {
+ ServiceCreator.closeAll();
+ super.tearDown();
+ }
+
+ public void testForwardAll() throws Exception
+ {
+ while (run < 10)
+ {
+ int services = 2;
+ ServiceCreator.start("vm://:1", services);
+
+ _logger.info("Starting " + ++run + " client...");
+
+ new Client("vm://:1", services).shutdownWhenComplete();
+
+
+ _logger.info("Completed " + run + " successfully!");
+ }
+ }
+
+ public static junit.framework.Test suite()
+ {
+ return new VMBrokerSetup(new junit.framework.TestSuite(CombinedTest.class));
+ }
+}
diff --git a/Final/java/client/src/test/java/org/apache/qpid/test/unit/client/forwardall/Service.java b/Final/java/client/src/test/java/org/apache/qpid/test/unit/client/forwardall/Service.java
new file mode 100644
index 0000000000..6593f7d86a
--- /dev/null
+++ b/Final/java/client/src/test/java/org/apache/qpid/test/unit/client/forwardall/Service.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.test.unit.client.forwardall;
+
+import javax.jms.Destination;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageListener;
+
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.client.AMQQueue;
+import org.apache.qpid.client.AMQSession;
+
+/**
+ * Declare a queue and bind it to amq.direct with a 'well known' routing key,
+ * register a consumer for this queue and send a response to every message received.
+ */
+public class Service implements MessageListener
+{
+ private final AMQConnection _connection;
+ private final AMQSession _session;
+
+ Service(String broker) throws Exception
+ {
+ this(connect(broker));
+ }
+
+ Service(AMQConnection connection) throws Exception
+ {
+ _connection = connection;
+ AMQQueue queue = new SpecialQueue(connection, "ServiceQueue");
+ _session = (AMQSession) _connection.createSession(false, AMQSession.NO_ACKNOWLEDGE);
+ _session.createConsumer(queue).setMessageListener(this);
+ _connection.start();
+ }
+
+ public void onMessage(Message request)
+ {
+ try
+ {
+ Message response = _session.createTextMessage("Response!");
+ Destination replyTo = request.getJMSReplyTo();
+ _session.createProducer(replyTo).send(response);
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace(System.out);
+ }
+ }
+
+ public void close() throws JMSException
+ {
+ _connection.close();
+ }
+
+ static AMQConnection connect(String broker) throws Exception
+ {
+ return new AMQConnection(broker, "guest", "guest", "Client" + System.currentTimeMillis(), "test");
+ }
+
+// public static void main(String[] argv) throws Exception
+// {
+// String broker = argv.length == 0? "localhost:5672" : argv[0];
+// new Service(broker);
+// }
+}
diff --git a/Final/java/client/src/test/java/org/apache/qpid/test/unit/client/forwardall/ServiceCreator.java b/Final/java/client/src/test/java/org/apache/qpid/test/unit/client/forwardall/ServiceCreator.java
new file mode 100644
index 0000000000..be16f6b7ae
--- /dev/null
+++ b/Final/java/client/src/test/java/org/apache/qpid/test/unit/client/forwardall/ServiceCreator.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.unit.client.forwardall;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.jms.JMSException;
+
+public class ServiceCreator implements Runnable
+{
+ private static final Logger _logger = LoggerFactory.getLogger(ServiceCreator.class);
+
+ private static Thread[] threads;
+ private static ServiceCreator[] _services;
+
+ private final String broker;
+ private Service service;
+
+ ServiceCreator(String broker)
+ {
+ this.broker = broker;
+ }
+
+ public void run()
+ {
+ try
+ {
+ service = new Service(broker);
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace(System.out);
+ }
+ }
+
+ public void closeSC() throws JMSException
+ {
+ service.close();
+ }
+
+ static void closeAll()
+ {
+ for (int i = 0; i < _services.length; i++)
+ {
+ try
+ {
+ _services[i].closeSC();
+ }
+ catch (JMSException e)
+ {
+ // ignore
+ }
+ }
+ }
+
+ static void start(String broker, int services) throws InterruptedException
+ {
+ threads = new Thread[services];
+ _services = new ServiceCreator[services];
+ ServiceCreator runner = new ServiceCreator(broker);
+ // start services
+ _logger.info("Starting " + services + " services...");
+ for (int i = 0; i < services; i++)
+ {
+ threads[i] = new Thread(runner);
+ _services[i] = runner;
+ threads[i].start();
+ }
+
+ for (int i = 0; i < threads.length; i++)
+ {
+ threads[i].join();
+ }
+ }
+
+ public static void main(String[] argv) throws Exception
+ {
+ final String connectionString;
+ final int services;
+ if (argv.length == 0)
+ {
+ connectionString = "localhost:5672";
+ services = 100;
+ }
+ else
+ {
+ connectionString = argv[0];
+ services = Integer.parseInt(argv[1]);
+ }
+
+ start(connectionString, services);
+ }
+}
diff --git a/Final/java/client/src/test/java/org/apache/qpid/test/unit/client/forwardall/SpecialQueue.java b/Final/java/client/src/test/java/org/apache/qpid/test/unit/client/forwardall/SpecialQueue.java
new file mode 100644
index 0000000000..27371b0397
--- /dev/null
+++ b/Final/java/client/src/test/java/org/apache/qpid/test/unit/client/forwardall/SpecialQueue.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.test.unit.client.forwardall;
+
+import org.apache.qpid.client.AMQQueue;
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.framing.AMQShortString;
+
+/**
+ * Queue that allows several private queues to be registered and bound
+ * to an exchange with the same routing key.
+ *
+ */
+class SpecialQueue extends AMQQueue
+{
+ private final AMQShortString name;
+
+ SpecialQueue(AMQConnection con, String name)
+ {
+ super(con, name, true);
+ this.name = new AMQShortString(name);
+ }
+
+ public AMQShortString getRoutingKey()
+ {
+ return name;
+ }
+}
diff --git a/Final/java/client/src/test/java/org/apache/qpid/test/unit/client/message/BytesMessageTest.java b/Final/java/client/src/test/java/org/apache/qpid/test/unit/client/message/BytesMessageTest.java
new file mode 100644
index 0000000000..bbabf0b57d
--- /dev/null
+++ b/Final/java/client/src/test/java/org/apache/qpid/test/unit/client/message/BytesMessageTest.java
@@ -0,0 +1,569 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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.message;
+
+import java.util.HashMap;
+
+import javax.jms.MessageEOFException;
+import javax.jms.MessageFormatException;
+import javax.jms.MessageNotReadableException;
+import javax.jms.MessageNotWriteableException;
+
+import junit.framework.TestCase;
+
+import org.apache.qpid.client.message.JMSBytesMessage;
+import org.apache.qpid.client.message.TestMessageHelper;
+
+public class BytesMessageTest extends TestCase
+{
+ /**
+ * Tests that on creation a call to getBodyLength() throws an exception
+ * if null was passed in during creation
+ */
+ public void testNotReadableOnCreationWithNull() throws Exception
+ {
+ try
+ {
+ JMSBytesMessage bm = TestMessageHelper.newJMSBytesMessage();
+ bm.getBodyLength();
+ fail("expected exception did not occur");
+ }
+ catch (MessageNotReadableException m)
+ {
+ // ok
+ }
+ catch (Exception e)
+ {
+ fail("expected MessageNotReadableException, got " + e);
+ }
+ }
+
+ public void testResetMakesReadble() throws Exception
+ {
+ try
+ {
+ JMSBytesMessage bm = TestMessageHelper.newJMSBytesMessage();
+ bm.writeInt(10);
+ bm.reset();
+ bm.writeInt(12);
+ fail("expected exception did not occur");
+ }
+ catch (MessageNotWriteableException m)
+ {
+ // ok
+ }
+ catch (Exception e)
+ {
+ fail("expected MessageNotWriteableException, got " + e);
+ }
+ }
+
+ public void testClearBodyMakesWritable() throws Exception
+ {
+ JMSBytesMessage bm = TestMessageHelper.newJMSBytesMessage();
+ bm.writeInt(10);
+ bm.reset();
+ bm.clearBody();
+ bm.writeInt(10);
+ }
+
+ public void testWriteBoolean() throws Exception
+ {
+ JMSBytesMessage bm = TestMessageHelper.newJMSBytesMessage();
+ bm.writeBoolean(true);
+ bm.writeBoolean(false);
+ bm.reset();
+ boolean val = bm.readBoolean();
+ assertEquals(true, val);
+ val = bm.readBoolean();
+ assertEquals(false, val);
+ }
+
+ public void testWriteInt() throws Exception
+ {
+ JMSBytesMessage bm = TestMessageHelper.newJMSBytesMessage();
+ bm.writeInt(10);
+ bm.reset();
+ long len = bm.getBodyLength();
+ assertTrue(len == 4);
+ int val = bm.readInt();
+ assertTrue(val == 10);
+ }
+
+ public void testWriteString() throws Exception
+ {
+ JMSBytesMessage bm = TestMessageHelper.newJMSBytesMessage();
+ bm.writeUTF("Bananas");
+ bm.reset();
+ String res = bm.readUTF();
+ assertEquals("Bananas", res);
+ }
+
+ public void testWriteBytes() throws Exception
+ {
+ JMSBytesMessage bm = TestMessageHelper.newJMSBytesMessage();
+ byte[] bytes = {1,2,3,4};
+ bm.writeBytes(bytes, 1, 2);
+ bm.reset();
+ bytes = new byte[2];
+ bm.readBytes(bytes);
+ assertEquals(2, bytes[0]);
+ assertEquals(3, bytes[1]);
+ }
+
+ public void testWriteObject() throws Exception
+ {
+ JMSBytesMessage bm = TestMessageHelper.newJMSBytesMessage();
+ bm.writeObject(new Boolean(true));
+ bm.writeObject(new Boolean(false));
+ bm.writeObject(new Byte((byte)2));
+ bm.writeObject(new byte[]{1,2,3,4});
+ bm.writeObject(new Character('g'));
+ bm.writeObject(new Short((short) 29));
+ bm.writeObject(new Integer(101));
+ bm.writeObject(new Long(50003222L));
+ bm.writeObject("Foobar");
+ bm.writeObject(new Float(1.7f));
+ bm.writeObject(new Double(8.7d));
+ bm.reset();
+ assertTrue(bm.readBoolean());
+ assertTrue(!bm.readBoolean());
+ assertEquals((byte)2, bm.readByte());
+ byte[] bytes = new byte[4];
+ bm.readBytes(bytes);
+ assertEquals('g', bm.readChar());
+ assertEquals((short) 29, bm.readShort());
+ assertEquals(101, bm.readInt());
+ assertEquals(50003222L, bm.readLong());
+ assertEquals("Foobar", bm.readUTF());
+ assertEquals(1.7f, bm.readFloat());
+ assertEquals(8.7d, bm.readDouble());
+ }
+
+ public void testWriteObjectRejectsNonPrimitives() throws Exception
+ {
+ try
+ {
+ JMSBytesMessage bm = TestMessageHelper.newJMSBytesMessage();
+ bm.writeObject(new HashMap());
+ fail("expected MessageFormatException was not thrown");
+ }
+ catch (MessageFormatException e)
+ {
+ // pass
+ }
+ }
+
+ public void testWriteObjectThrowsNPE() throws Exception
+ {
+ try
+ {
+ JMSBytesMessage bm = TestMessageHelper.newJMSBytesMessage();
+ bm.writeObject(null);
+ fail("expected exception did not occur");
+ }
+ catch (NullPointerException n)
+ {
+ // ok
+ }
+ catch (Exception e)
+ {
+ fail("expected NullPointerException, got " + e);
+ }
+ }
+
+ public void testReadBoolean() throws Exception
+ {
+ JMSBytesMessage bm = TestMessageHelper.newJMSBytesMessage();
+ bm.writeBoolean(true);
+ bm.reset();
+ boolean result = bm.readBoolean();
+ assertTrue(result);
+ }
+
+ public void testReadUnsignedByte() throws Exception
+ {
+ JMSBytesMessage bm = TestMessageHelper.newJMSBytesMessage();
+ bm.writeByte((byte) 9);
+ bm.reset();
+ int result = bm.readUnsignedByte();
+ assertEquals(9, result);
+ }
+
+ public void testReadUnsignedShort() throws Exception
+ {
+ JMSBytesMessage bm = TestMessageHelper.newJMSBytesMessage();
+ bm.writeShort((byte) 9);
+ bm.reset();
+ int result = bm.readUnsignedShort();
+ assertEquals(9, result);
+ }
+
+ public void testReadBytesChecksNull() throws Exception
+ {
+ try
+ {
+ JMSBytesMessage bm = TestMessageHelper.newJMSBytesMessage();
+ bm.readBytes(null);
+ }
+ catch (IllegalArgumentException e)
+ {
+ // pass
+ }
+
+ try
+ {
+ JMSBytesMessage bm = TestMessageHelper.newJMSBytesMessage();
+ bm.readBytes(null, 1);
+ }
+ catch (IllegalArgumentException e)
+ {
+ // pass
+ }
+ }
+
+ public void testReadBytesChecksMaxSize() throws Exception
+ {
+ try
+ {
+ JMSBytesMessage bm = TestMessageHelper.newJMSBytesMessage();
+ byte[] bytes = new byte[100];
+ bm.readBytes(bytes, 120);
+ }
+ catch (IllegalArgumentException e)
+ {
+ // pass
+ }
+ }
+
+ public void testReadBytesReturnsCorrectLengths() throws Exception
+ {
+ JMSBytesMessage bm = TestMessageHelper.newJMSBytesMessage();
+ byte[] bytes = {2, 3};
+ bm.writeBytes(bytes);
+ bm.reset();
+ int len = bm.readBytes(bytes);
+ assertEquals(2, len);
+ len = bm.readBytes(bytes);
+ assertEquals(-1, len);
+ len = bm.readBytes(bytes, 2);
+ assertEquals(-1, len);
+ bm.reset();
+ len = bm.readBytes(bytes, 2);
+ assertEquals(2, len);
+ bm.reset();
+ len = bm.readBytes(bytes, 1);
+ assertEquals(1, len);
+
+ }
+
+ public void testEOFByte() throws Exception
+ {
+ try
+ {
+ JMSBytesMessage bm = TestMessageHelper.newJMSBytesMessage();
+ bm.writeByte((byte)1);
+ bm.reset();
+ bm.readByte();
+ // should throw
+ bm.readByte();
+ fail("expected exception did not occur");
+ }
+ catch (MessageEOFException m)
+ {
+ // ok
+ }
+ catch (Exception e)
+ {
+ fail("expected MessageEOFException, got " + e);
+ }
+ }
+
+ public void testEOFUnsignedByte() throws Exception
+ {
+ try
+ {
+ JMSBytesMessage bm = TestMessageHelper.newJMSBytesMessage();
+ bm.writeByte((byte)1);
+ bm.reset();
+ bm.readByte();
+ // should throw
+ bm.readUnsignedByte();
+ fail("expected exception did not occur");
+ }
+ catch (MessageEOFException m)
+ {
+ // ok
+ }
+ catch (Exception e)
+ {
+ fail("expected MessageEOFException, got " + e);
+ }
+ }
+
+ public void testEOFBoolean() throws Exception
+ {
+ try
+ {
+ JMSBytesMessage bm = TestMessageHelper.newJMSBytesMessage();
+ bm.writeBoolean(true);
+ bm.reset();
+ bm.readBoolean();
+ // should throw
+ bm.readBoolean();
+ fail("expected exception did not occur");
+ }
+ catch (MessageEOFException m)
+ {
+ // ok
+ }
+ catch (Exception e)
+ {
+ fail("expected MessageEOFException, got " + e);
+ }
+ }
+
+ public void testEOFChar() throws Exception
+ {
+ try
+ {
+ JMSBytesMessage bm = TestMessageHelper.newJMSBytesMessage();
+ bm.writeChar('A');
+ bm.reset();
+ bm.readChar();
+ // should throw
+ bm.readChar();
+ fail("expected exception did not occur");
+ }
+ catch (MessageEOFException m)
+ {
+ // ok
+ }
+ catch (Exception e)
+ {
+ fail("expected MessageEOFException, got " + e);
+ }
+ }
+
+ public void testEOFDouble() throws Exception
+ {
+ try
+ {
+ JMSBytesMessage bm = TestMessageHelper.newJMSBytesMessage();
+ bm.writeDouble(1.3d);
+ bm.reset();
+ bm.readDouble();
+ // should throw
+ bm.readDouble();
+ fail("expected exception did not occur");
+ }
+ catch (MessageEOFException m)
+ {
+ // ok
+ }
+ catch (Exception e)
+ {
+ fail("expected MessageEOFException, got " + e);
+ }
+ }
+
+ public void testEOFFloat() throws Exception
+ {
+ try
+ {
+ JMSBytesMessage bm = TestMessageHelper.newJMSBytesMessage();
+ bm.writeFloat(1.3f);
+ bm.reset();
+ bm.readFloat();
+ // should throw
+ bm.readFloat();
+ fail("expected exception did not occur");
+ }
+ catch (MessageEOFException m)
+ {
+ // ok
+ }
+ catch (Exception e)
+ {
+ fail("expected MessageEOFException, got " + e);
+ }
+ }
+
+ public void testEOFInt() throws Exception
+ {
+ try
+ {
+ JMSBytesMessage bm = TestMessageHelper.newJMSBytesMessage();
+ bm.writeInt(99);
+ bm.reset();
+ bm.readInt();
+ // should throw
+ bm.readInt();
+ fail("expected exception did not occur");
+ }
+ catch (MessageEOFException m)
+ {
+ // ok
+ }
+ catch (Exception e)
+ {
+ fail("expected MessageEOFException, got " + e);
+ }
+ }
+
+ public void testEOFLong() throws Exception
+ {
+ try
+ {
+ JMSBytesMessage bm = TestMessageHelper.newJMSBytesMessage();
+ bm.writeLong(4L);
+ bm.reset();
+ bm.readLong();
+ // should throw
+ bm.readLong();
+ fail("expected exception did not occur");
+ }
+ catch (MessageEOFException m)
+ {
+ // ok
+ }
+ catch (Exception e)
+ {
+ fail("expected MessageEOFException, got " + e);
+ }
+ }
+
+ public void testEOFShort() throws Exception
+ {
+ try
+ {
+ JMSBytesMessage bm = TestMessageHelper.newJMSBytesMessage();
+ bm.writeShort((short)4);
+ bm.reset();
+ bm.readShort();
+ // should throw
+ bm.readShort();
+ fail("expected exception did not occur");
+ }
+ catch (MessageEOFException m)
+ {
+ // ok
+ }
+ catch (Exception e)
+ {
+ fail("expected MessageEOFException, got " + e);
+ }
+ }
+
+ public void testEOFUnsignedShort() throws Exception
+ {
+ try
+ {
+ JMSBytesMessage bm = TestMessageHelper.newJMSBytesMessage();
+ bm.writeShort((short)4);
+ bm.reset();
+ bm.readUnsignedShort();
+ // should throw
+ bm.readUnsignedShort();
+ fail("expected exception did not occur");
+ }
+ catch (MessageEOFException m)
+ {
+ // ok
+ }
+ catch (Exception e)
+ {
+ fail("expected MessageEOFException, got " + e);
+ }
+ }
+
+ /**
+ * Tests that the readBytes() method populates the passed in array
+ * correctly
+ * @throws Exception
+ */
+ public void testReadBytes() throws Exception
+ {
+ JMSBytesMessage bm = TestMessageHelper.newJMSBytesMessage();
+ bm.writeByte((byte)3);
+ bm.writeByte((byte)4);
+ bm.reset();
+ byte[] result = new byte[2];
+ int count = bm.readBytes(result);
+ assertEquals((byte)3, result[0]);
+ assertEquals((byte)4, result[1]);
+ assertEquals(2, count);
+ }
+
+ public void testReadBytesEOF() throws Exception
+ {
+ JMSBytesMessage bm = TestMessageHelper.newJMSBytesMessage();
+ bm.writeByte((byte)3);
+ bm.writeByte((byte)4);
+ bm.reset();
+ byte[] result = new byte[2];
+ bm.readBytes(result);
+ int count = bm.readBytes(result);
+ assertEquals(-1, count);
+ }
+
+ public void testReadBytesWithLargerArray() throws Exception
+ {
+ JMSBytesMessage bm = TestMessageHelper.newJMSBytesMessage();
+ bm.writeByte((byte)3);
+ bm.writeByte((byte)4);
+ bm.reset();
+ byte[] result = new byte[3];
+ int count = bm.readBytes(result);
+ assertEquals(2, count);
+ assertEquals((byte)3, result[0]);
+ assertEquals((byte)4, result[1]);
+ assertEquals((byte)0, result[2]);
+ }
+
+ public void testReadBytesWithCount() throws Exception
+ {
+ JMSBytesMessage bm = TestMessageHelper.newJMSBytesMessage();
+ bm.writeByte((byte)3);
+ bm.writeByte((byte)4);
+ bm.writeByte((byte)5);
+ bm.reset();
+ byte[] result = new byte[3];
+ int count = bm.readBytes(result, 2);
+ assertEquals(2, count);
+ assertEquals((byte)3, result[0]);
+ assertEquals((byte)4, result[1]);
+ assertEquals((byte)0, result[2]);
+ }
+
+ public void testToBodyStringWithNull() throws Exception
+ {
+ JMSBytesMessage bm = TestMessageHelper.newJMSBytesMessage();
+ bm.reset();
+ String result = bm.toBodyString();
+ assertNull(result);
+ }
+
+ public static junit.framework.Test suite()
+ {
+ return new junit.framework.TestSuite(BytesMessageTest.class);
+ }
+}
diff --git a/Final/java/client/src/test/java/org/apache/qpid/test/unit/client/message/MapMessageTest.java b/Final/java/client/src/test/java/org/apache/qpid/test/unit/client/message/MapMessageTest.java
new file mode 100644
index 0000000000..3e04c36b38
--- /dev/null
+++ b/Final/java/client/src/test/java/org/apache/qpid/test/unit/client/message/MapMessageTest.java
@@ -0,0 +1,383 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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.message;
+
+import javax.jms.JMSException;
+import javax.jms.MessageFormatException;
+
+import junit.framework.Assert;
+import junit.framework.TestCase;
+
+import org.apache.qpid.client.message.JMSMapMessage;
+import org.apache.qpid.client.message.TestMessageHelper;
+
+
+public class MapMessageTest extends TestCase
+{
+
+ //Test Lookups
+
+ public void testBooleanLookup()
+ {
+ try
+ {
+ JMSMapMessage mm = TestMessageHelper.newJMSMapMessage();
+
+ mm.setBoolean("value", true);
+ Assert.assertEquals(true, mm.getBoolean("value"));
+ Assert.assertEquals("true", mm.getString("value"));
+ }
+ catch (JMSException e)
+ {
+ Assert.fail("JMSException received." + e);
+ }
+ }
+
+ public void testByteLookup()
+ {
+ try
+ {
+ JMSMapMessage mm = TestMessageHelper.newJMSMapMessage();
+ mm.setByte("value", Byte.MAX_VALUE);
+
+ Assert.assertEquals(Byte.MAX_VALUE, mm.getByte("value"));
+ Assert.assertEquals((short) Byte.MAX_VALUE, mm.getShort("value"));
+ Assert.assertEquals(Byte.MAX_VALUE, mm.getInt("value"));
+ Assert.assertEquals((long) Byte.MAX_VALUE, mm.getLong("value"));
+ Assert.assertEquals("" + Byte.MAX_VALUE, mm.getString("value"));
+
+ }
+ catch (JMSException e)
+ {
+ Assert.fail("JMSException received." + e);
+ }
+ }
+
+ public void testShortLookup()
+ {
+ try
+ {
+ JMSMapMessage mm = TestMessageHelper.newJMSMapMessage();
+ mm.setShort("value", Short.MAX_VALUE);
+ Assert.assertEquals(Short.MAX_VALUE, mm.getShort("value"));
+ Assert.assertEquals((int) Short.MAX_VALUE, mm.getInt("value"));
+ Assert.assertEquals((long) Short.MAX_VALUE, mm.getLong("value"));
+ Assert.assertEquals("" + Short.MAX_VALUE, mm.getString("value"));
+ }
+ catch (JMSException e)
+ {
+ Assert.fail("JMSException received." + e);
+ }
+ }
+
+
+ public void testCharLookup()
+ {
+ try
+ {
+ JMSMapMessage mm = TestMessageHelper.newJMSMapMessage();
+
+ mm.setChar("value", 'c');
+ Assert.assertEquals('c', mm.getChar("value"));
+ Assert.assertEquals("c", mm.getString("value"));
+ }
+ catch (JMSException e)
+ {
+ Assert.fail("JMSException received." + e);
+ }
+
+ try
+ {
+ JMSMapMessage mm = TestMessageHelper.newJMSMapMessage();
+
+ mm.setString("value", null);
+ mm.getChar("value");
+ fail("Expected NullPointerException");
+
+ }
+ catch (NullPointerException e)
+ {
+ ; // pass
+ }
+ catch (JMSException e)
+ {
+ Assert.fail("JMSException received." + e);
+ }
+
+
+
+ }
+
+ public void testDoubleLookup()
+ {
+ try
+ {
+ JMSMapMessage mm = TestMessageHelper.newJMSMapMessage();
+ mm.setDouble("value", Double.MAX_VALUE);
+ Assert.assertEquals(Double.MAX_VALUE, mm.getDouble("value"));
+ Assert.assertEquals("" + Double.MAX_VALUE, mm.getString("value"));
+ }
+ catch (JMSException e)
+ {
+ Assert.fail("JMSException received." + e);
+ }
+ }
+
+ public void testFloatLookup()
+ {
+ try
+ {
+ JMSMapMessage mm = TestMessageHelper.newJMSMapMessage();
+ mm.setFloat("value", Float.MAX_VALUE);
+ Assert.assertEquals(Float.MAX_VALUE, mm.getFloat("value"));
+ Assert.assertEquals((double) Float.MAX_VALUE, mm.getDouble("value"));
+ Assert.assertEquals("" + Float.MAX_VALUE, mm.getString("value"));
+ }
+ catch (JMSException e)
+ {
+ Assert.fail("JMSException received." + e);
+ }
+ }
+
+ public void testIntLookup()
+ {
+ try
+ {
+ JMSMapMessage mm = TestMessageHelper.newJMSMapMessage();
+ mm.setInt("value", Integer.MAX_VALUE);
+ Assert.assertEquals(Integer.MAX_VALUE, mm.getInt("value"));
+ Assert.assertEquals((long) Integer.MAX_VALUE, mm.getLong("value"));
+ Assert.assertEquals("" + Integer.MAX_VALUE, mm.getString("value"));
+ }
+ catch (JMSException e)
+ {
+ Assert.fail("JMSException received." + e);
+ }
+ }
+
+ public void testLongLookup()
+ {
+ try
+ {
+ JMSMapMessage mm = TestMessageHelper.newJMSMapMessage();
+ mm.setLong("value", Long.MAX_VALUE);
+ Assert.assertEquals(Long.MAX_VALUE, mm.getLong("value"));
+ Assert.assertEquals("" + Long.MAX_VALUE, mm.getString("value"));
+ }
+ catch (JMSException e)
+ {
+ Assert.fail("JMSException received." + e);
+ }
+ }
+
+ public void testBytesLookup()
+ {
+ try
+ {
+ JMSMapMessage mm = TestMessageHelper.newJMSMapMessage();
+ byte[] bytes = {99, 98, 97, 96, 95};
+ mm.setBytes("bytes", bytes);
+ assertBytesEqual(bytes, mm.getBytes("bytes"));
+ }
+ catch (JMSException e)
+ {
+ Assert.fail("JMSException received." + e);
+ }
+ }
+
+ // Failed Lookups
+
+ public void testFailedBooleanLookup()
+ {
+ try
+ {
+ JMSMapMessage mm = TestMessageHelper.newJMSMapMessage();
+ Assert.assertEquals(false, mm.getBoolean("int"));
+ }
+ catch (JMSException e)
+ {
+ Assert.fail("JMSException received." + e);
+ }
+ }
+
+ public void testFailedByteLookup()
+ {
+ try
+ {
+ JMSMapMessage mm = TestMessageHelper.newJMSMapMessage();
+ mm.getByte("random");
+ Assert.fail("NumberFormatException expected");
+ }
+ catch (NumberFormatException e)
+ {
+ //normal execution
+ }
+ catch (JMSException e)
+ {
+ Assert.fail("JMSException received:" + e);
+ }
+
+ }
+
+ public void testFailedBytesLookup()
+ {
+ try
+ {
+ JMSMapMessage mm = TestMessageHelper.newJMSMapMessage();
+ mm.getBytes("random");
+ Assert.fail("MessageFormatException expected");
+ }
+ catch (MessageFormatException mfe)
+ {
+ //normal path
+ }
+ catch (JMSException e)
+ {
+ Assert.fail("JMSException received:" + e);
+ }
+ }
+
+ public void testFailedCharLookup()
+ {
+ try
+ {
+ JMSMapMessage mm = TestMessageHelper.newJMSMapMessage();
+ mm.getChar("random");
+ Assert.fail("MessageFormatException expected");
+ }
+ catch (MessageFormatException e)
+ {
+ //normal execution
+ }
+ catch (JMSException e)
+ {
+ Assert.fail("JMSException received:" + e);
+ }
+ }
+
+ public void testFailedDoubleLookup()
+ {
+ try
+ {
+ JMSMapMessage mm = TestMessageHelper.newJMSMapMessage();
+ mm.getDouble("random");
+ Assert.fail("NullPointerException should be received.");
+ }
+ catch (NullPointerException e)
+ {
+ //normal execution
+ }
+ catch (JMSException e)
+ {
+ Assert.fail("JMSException received:" + e);
+ }
+ }
+
+ public void testFailedFloatLookup()
+ {
+ try
+ {
+ JMSMapMessage mm = TestMessageHelper.newJMSMapMessage();
+ mm.getFloat("random");
+ Assert.fail("NullPointerException should be received.");
+ }
+ catch (NullPointerException e)
+ {
+ //normal execution
+ }
+ catch (JMSException e)
+ {
+ Assert.fail("JMSException received:" + e);
+ }
+ }
+
+ public void testFailedIntLookup()
+ {
+ try
+ {
+ JMSMapMessage mm = TestMessageHelper.newJMSMapMessage();
+ mm.getInt("random");
+ Assert.fail("NumberFormatException should be received.");
+ }
+ catch (NumberFormatException e)
+ {
+ //normal execution
+ }
+ catch (JMSException e)
+ {
+ Assert.fail("JMSException received:" + e);
+ }
+ }
+
+ public void testFailedLongLookup()
+ {
+ try
+ {
+ JMSMapMessage mm = TestMessageHelper.newJMSMapMessage();
+ mm.getLong("random");
+ Assert.fail("NumberFormatException should be received.");
+ }
+ catch (NumberFormatException e)
+ {
+ //normal execution
+ }
+ catch (JMSException e)
+ {
+ Assert.fail("JMSException received:" + e);
+ }
+ }
+
+ public void testFailedShortLookup()
+ {
+ try
+ {
+ JMSMapMessage mm = TestMessageHelper.newJMSMapMessage();
+ mm.getShort("random");
+ Assert.fail("NumberFormatException should be received.");
+ }
+ catch (NumberFormatException e)
+ {
+ //normal execution
+ }
+ catch (JMSException e)
+ {
+ Assert.fail("JMSException received:" + e);
+ }
+ }
+
+
+ private void assertBytesEqual(byte[] expected, byte[] actual)
+ {
+ Assert.assertEquals(expected.length, actual.length);
+
+ for (int index = 0; index < expected.length; index++)
+ {
+ Assert.assertEquals(expected[index], actual[index]);
+ }
+ }
+
+ public static junit.framework.Test suite()
+ {
+ return new junit.framework.TestSuite(MapMessageTest.class);
+ }
+
+
+}
diff --git a/Final/java/client/src/test/java/org/apache/qpid/test/unit/client/message/ObjectMessageTest.java b/Final/java/client/src/test/java/org/apache/qpid/test/unit/client/message/ObjectMessageTest.java
new file mode 100644
index 0000000000..cd03b523d1
--- /dev/null
+++ b/Final/java/client/src/test/java/org/apache/qpid/test/unit/client/message/ObjectMessageTest.java
@@ -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.
+ *
+ */
+package org.apache.qpid.test.unit.client.message;
+
+import junit.framework.TestCase;
+
+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.testutil.VMBrokerSetup;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageListener;
+import javax.jms.MessageProducer;
+import javax.jms.ObjectMessage;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+
+public class ObjectMessageTest extends TestCase implements MessageListener
+{
+ private static final Logger _logger = LoggerFactory.getLogger(ObjectMessageTest.class);
+
+ private AMQConnection connection;
+ private AMQDestination destination;
+ private AMQSession session;
+ private MessageProducer producer;
+ private Serializable[] data;
+ private volatile boolean waiting;
+ private int received;
+ private final ArrayList items = new ArrayList();
+
+ private String _broker = "vm://:1";
+
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+ connection = new AMQConnection(_broker, "guest", "guest", randomize("Client"), "test");
+ destination = new AMQQueue(connection, randomize("LatencyTest"), true);
+ session = (AMQSession) connection.createSession(false, AMQSession.NO_ACKNOWLEDGE);
+
+ // set up a consumer
+ session.createConsumer(destination).setMessageListener(this);
+ connection.start();
+
+ // create a publisher
+ producer = session.createProducer(destination, false, false, true);
+ A a1 = new A(1, "A");
+ A a2 = new A(2, "a");
+ B b = new B(1, "B");
+ C c = new C();
+ c.put("A1", a1);
+ c.put("a2", a2);
+ c.put("B", b);
+ c.put("String", "String");
+
+ data = new Serializable[] { a1, a2, b, c, "Hello World!", new Integer(1001) };
+ }
+
+ protected void tearDown() throws Exception
+ {
+ super.tearDown();
+ }
+
+ public ObjectMessageTest()
+ { }
+
+ ObjectMessageTest(String broker) throws Exception
+ {
+ _broker = broker;
+ }
+
+ public void testSendAndReceive() throws Exception
+ {
+ try
+ {
+ send();
+ waitUntilReceived(data.length);
+ check();
+ _logger.info("All " + data.length + " items matched.");
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ fail("This Test should succeed but failed due to: " + e);
+ }
+ finally
+ {
+ close();
+ }
+ }
+
+ public void testSetObjectPropertyForString() throws Exception
+ {
+ String testStringProperty = "TestStringProperty";
+ ObjectMessage msg = session.createObjectMessage(data[0]);
+ msg.setObjectProperty("TestStringProperty", testStringProperty);
+ assertEquals(testStringProperty, msg.getObjectProperty("TestStringProperty"));
+ }
+
+ public void testSetObjectPropertyForBoolean() throws Exception
+ {
+ ObjectMessage msg = session.createObjectMessage(data[0]);
+ msg.setObjectProperty("TestBooleanProperty", Boolean.TRUE);
+ assertEquals(Boolean.TRUE, msg.getObjectProperty("TestBooleanProperty"));
+ }
+
+ public void testSetObjectPropertyForByte() throws Exception
+ {
+ ObjectMessage msg = session.createObjectMessage(data[0]);
+ msg.setObjectProperty("TestByteProperty", Byte.MAX_VALUE);
+ assertEquals(Byte.MAX_VALUE, msg.getObjectProperty("TestByteProperty"));
+ }
+
+ public void testSetObjectPropertyForShort() throws Exception
+ {
+ ObjectMessage msg = session.createObjectMessage(data[0]);
+ msg.setObjectProperty("TestShortProperty", Short.MAX_VALUE);
+ assertEquals(Short.MAX_VALUE, msg.getObjectProperty("TestShortProperty"));
+ }
+
+ public void testSetObjectPropertyForInteger() throws Exception
+ {
+ ObjectMessage msg = session.createObjectMessage(data[0]);
+ msg.setObjectProperty("TestIntegerProperty", Integer.MAX_VALUE);
+ assertEquals(Integer.MAX_VALUE, msg.getObjectProperty("TestIntegerProperty"));
+ }
+
+ public void testSetObjectPropertyForDouble() throws Exception
+ {
+ ObjectMessage msg = session.createObjectMessage(data[0]);
+ msg.setObjectProperty("TestDoubleProperty", Double.MAX_VALUE);
+ assertEquals(Double.MAX_VALUE, msg.getObjectProperty("TestDoubleProperty"));
+ }
+
+ public void testSetObjectPropertyForFloat() throws Exception
+ {
+ ObjectMessage msg = session.createObjectMessage(data[0]);
+ msg.setObjectProperty("TestFloatProperty", Float.MAX_VALUE);
+ assertEquals(Float.MAX_VALUE, msg.getObjectProperty("TestFloatProperty"));
+ }
+
+ public void testSetObjectPropertyForByteArray() throws Exception
+ {
+ byte[] array = { 1, 2, 3, 4, 5 };
+ ObjectMessage msg = session.createObjectMessage(data[0]);
+ msg.setObjectProperty("TestByteArrayProperty", array);
+ assertTrue(Arrays.equals(array, (byte[]) msg.getObjectProperty("TestByteArrayProperty")));
+ }
+
+ public void testSetObjectForNull() throws Exception
+ {
+ ObjectMessage msg = session.createObjectMessage();
+ msg.setObject(null);
+ assertNull(msg.getObject());
+ }
+
+ private void send() throws Exception
+ {
+ for (int i = 0; i < data.length; i++)
+ {
+ ObjectMessage msg;
+ if ((i % 2) == 0)
+ {
+ msg = session.createObjectMessage(data[i]);
+ }
+ else
+ {
+ msg = session.createObjectMessage();
+ msg.setObject(data[i]);
+ }
+
+ producer.send(msg);
+ }
+ }
+
+ public void check() throws Exception
+ {
+ Object[] actual = (Object[]) items.toArray();
+ if (actual.length != data.length)
+ {
+ throw new Exception("Expected " + data.length + " objects, got " + actual.length);
+ }
+
+ for (int i = 0; i < data.length; i++)
+ {
+ if (actual[i] instanceof Exception)
+ {
+ throw new Exception("Error on receive of " + data[i], ((Exception) actual[i]));
+ }
+
+ if (actual[i] == null)
+ {
+ throw new Exception("Expected " + data[i] + " got null");
+ }
+
+ if (!data[i].equals(actual[i]))
+ {
+ throw new Exception("Expected " + data[i] + " got " + actual[i]);
+ }
+ }
+ }
+
+ private void close() throws Exception
+ {
+ session.close();
+ connection.close();
+ }
+
+ private synchronized void waitUntilReceived(int count) throws InterruptedException
+ {
+ waiting = true;
+ while (received < count)
+ {
+ wait();
+ }
+
+ waiting = false;
+ }
+
+ public void onMessage(Message message)
+ {
+
+ try
+ {
+ if (message instanceof ObjectMessage)
+ {
+ items.add(((ObjectMessage) message).getObject());
+ }
+ else
+ {
+ _logger.error("ERROR: Got " + message.getClass().getName() + " not ObjectMessage");
+ items.add(message);
+ }
+ }
+ catch (JMSException e)
+ {
+ e.printStackTrace();
+ items.add(e);
+ }
+
+ synchronized (this)
+ {
+ received++;
+ notify();
+ }
+ }
+
+ public static void main(String[] argv) throws Exception
+ {
+ String broker = (argv.length > 0) ? argv[0] : "vm://:1";
+ if ("-help".equals(broker))
+ {
+ System.out.println("Usage: <broker>");
+ }
+
+ new ObjectMessageTest(broker).testSendAndReceive();
+ }
+
+ private static class A implements Serializable
+ {
+ private String sValue;
+ private int iValue;
+
+ A(int i, String s)
+ {
+ sValue = s;
+ iValue = i;
+ }
+
+ public int hashCode()
+ {
+ return iValue;
+ }
+
+ public boolean equals(Object o)
+ {
+ return (o instanceof A) && equals((A) o);
+ }
+
+ protected boolean equals(A a)
+ {
+ return areEqual(a.sValue, sValue) && (a.iValue == iValue);
+ }
+ }
+
+ private static class B extends A
+ {
+ private long time;
+
+ B(int i, String s)
+ {
+ super(i, s);
+ time = System.currentTimeMillis();
+ }
+
+ protected boolean equals(A a)
+ {
+ return super.equals(a) && (a instanceof B) && (time == ((B) a).time);
+ }
+ }
+
+ private static class C extends HashMap implements Serializable
+ { }
+
+ private static boolean areEqual(Object a, Object b)
+ {
+ return (a == null) ? (b == null) : a.equals(b);
+ }
+
+ private static String randomize(String in)
+ {
+ return in + System.currentTimeMillis();
+ }
+
+ public static junit.framework.Test suite()
+ {
+ return new VMBrokerSetup(new junit.framework.TestSuite(ObjectMessageTest.class));
+ }
+}
diff --git a/Final/java/client/src/test/java/org/apache/qpid/test/unit/client/message/StreamMessageTest.java b/Final/java/client/src/test/java/org/apache/qpid/test/unit/client/message/StreamMessageTest.java
new file mode 100644
index 0000000000..802f1e6c2e
--- /dev/null
+++ b/Final/java/client/src/test/java/org/apache/qpid/test/unit/client/message/StreamMessageTest.java
@@ -0,0 +1,623 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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.message;
+
+import java.util.HashMap;
+
+import javax.jms.JMSException;
+import javax.jms.MessageEOFException;
+import javax.jms.MessageFormatException;
+import javax.jms.MessageNotReadableException;
+import javax.jms.MessageNotWriteableException;
+import javax.jms.StreamMessage;
+
+import junit.framework.TestCase;
+
+import org.apache.qpid.client.message.JMSStreamMessage;
+import org.apache.qpid.client.message.TestMessageHelper;
+
+/**
+ * @author Apache Software Foundation
+ */
+public class StreamMessageTest extends TestCase
+{
+ /**
+ * Tests that on creation a call to getBodyLength() throws an exception
+ * if null was passed in during creation
+ */
+ public void testNotReadableOnCreationWithNull() throws Exception
+ {
+ try
+ {
+ JMSStreamMessage bm = TestMessageHelper.newJMSStreamMessage();
+ bm.readByte();
+ fail("expected exception did not occur");
+ }
+ catch (MessageNotReadableException m)
+ {
+ // ok
+ }
+ catch (Exception e)
+ {
+ fail("expected MessageNotReadableException, got " + e);
+ }
+ }
+
+ public void testResetMakesReadble() throws Exception
+ {
+ try
+ {
+ JMSStreamMessage bm = TestMessageHelper.newJMSStreamMessage();
+ bm.writeInt(10);
+ bm.reset();
+ bm.writeInt(12);
+ fail("expected exception did not occur");
+ }
+ catch (MessageNotWriteableException m)
+ {
+ // ok
+ }
+ catch (Exception e)
+ {
+ fail("expected MessageNotWriteableException, got " + e);
+ }
+ }
+
+ public void testClearBodyMakesWritable() throws Exception
+ {
+ JMSStreamMessage bm = TestMessageHelper.newJMSStreamMessage();
+ bm.writeInt(10);
+ bm.reset();
+ bm.clearBody();
+ bm.writeInt(10);
+ }
+
+ public void testWriteBoolean() throws Exception
+ {
+ JMSStreamMessage bm = TestMessageHelper.newJMSStreamMessage();
+ bm.writeBoolean(true);
+ bm.writeBoolean(false);
+ bm.reset();
+ boolean val = bm.readBoolean();
+ assertEquals(true, val);
+ val = bm.readBoolean();
+ assertEquals(false, val);
+ }
+
+ public void testWriteInt() throws Exception
+ {
+ JMSStreamMessage bm = TestMessageHelper.newJMSStreamMessage();
+ bm.writeInt(10);
+ bm.reset();
+ int val = bm.readInt();
+ assertTrue(val == 10);
+ }
+
+ public void testWriteString() throws Exception
+ {
+ JMSStreamMessage bm = TestMessageHelper.newJMSStreamMessage();
+ bm.writeString("Bananas");
+ bm.reset();
+ String res = bm.readString();
+ assertEquals("Bananas", res);
+ }
+
+ public void testWriteBytes() throws Exception
+ {
+ JMSStreamMessage bm = TestMessageHelper.newJMSStreamMessage();
+ byte[] bytes = {1,2,3,4};
+ bm.writeBytes(bytes, 1, 2);
+ bm.reset();
+ bytes = new byte[2];
+ bm.readBytes(bytes);
+ assertEquals(2, bytes[0]);
+ assertEquals(3, bytes[1]);
+ }
+
+ public void testWriteObject() throws Exception
+ {
+ JMSStreamMessage bm = TestMessageHelper.newJMSStreamMessage();
+ bm.writeObject(new Boolean(true));
+ bm.writeObject(new Boolean(false));
+ bm.writeObject(new Byte((byte)2));
+ bm.writeObject(new byte[]{1,2,3,4});
+ bm.writeObject(new Character('g'));
+ bm.writeObject(new Short((short) 29));
+ bm.writeObject(new Integer(101));
+ bm.writeObject(new Long(50003222L));
+ bm.writeObject("Foobar");
+ bm.writeObject(new Float(1.7f));
+ bm.writeObject(new Double(8.7d));
+ bm.reset();
+ assertTrue(bm.readBoolean());
+ assertTrue(!bm.readBoolean());
+ assertEquals((byte)2, bm.readByte());
+ byte[] bytes = new byte[4];
+ bm.readBytes(bytes);
+ assertEquals('g', bm.readChar());
+ assertEquals((short) 29, bm.readShort());
+ assertEquals(101, bm.readInt());
+ assertEquals(50003222L, bm.readLong());
+ assertEquals("Foobar", bm.readString());
+ assertEquals(1.7f, bm.readFloat());
+ assertEquals(8.7d, bm.readDouble());
+ }
+
+ public void testWriteObjectRejectsNonPrimitives() throws Exception
+ {
+ try
+ {
+ JMSStreamMessage bm = TestMessageHelper.newJMSStreamMessage();
+ bm.writeObject(new HashMap());
+ fail("expected MessageFormatException was not thrown");
+ }
+ catch (MessageFormatException e)
+ {
+ // pass
+ }
+ }
+
+ public void testReadBoolean() throws Exception
+ {
+ JMSStreamMessage bm = TestMessageHelper.newJMSStreamMessage();
+ bm.writeBoolean(true);
+ bm.reset();
+ boolean result = bm.readBoolean();
+ assertTrue(result);
+ }
+
+ public void testReadBytesChecksNull() throws Exception
+ {
+ try
+ {
+ JMSStreamMessage bm = TestMessageHelper.newJMSStreamMessage();
+ bm.readBytes(null);
+ }
+ catch (IllegalArgumentException e)
+ {
+ // pass
+ }
+ }
+
+ public void testReadBytesReturnsCorrectLengths() throws Exception
+ {
+ JMSStreamMessage bm = TestMessageHelper.newJMSStreamMessage();
+ byte[] bytes = {2, 3};
+ bm.writeBytes(bytes);
+ bm.writeBytes(null);
+ bm.writeBytes(new byte[]{});
+ bm.reset();
+ int len = bm.readBytes(bytes);
+ assertEquals(2, len);
+ len = bm.readBytes(bytes);
+ assertEquals(-1, len);
+ len = bm.readBytes(bytes);
+ assertEquals(-1, len);
+ len = bm.readBytes(bytes);
+ assertEquals(0, len);
+ }
+
+ public void testReadBytesFollowedByPrimitive() throws Exception
+ {
+ JMSStreamMessage bm = TestMessageHelper.newJMSStreamMessage();
+ bm.writeBytes(new byte[]{2, 3, 4, 5, 6, 7, 8});
+ bm.writeBytes(new byte[]{2, 3, 4, 5, 6, 7});
+ bm.writeString("Foo");
+ bm.reset();
+ int len;
+ do
+ {
+ len = bm.readBytes(new byte[2]);
+ }
+ while (len == 2);
+
+ do
+ {
+ len = bm.readBytes(new byte[2]);
+ }
+ while (len == 2);
+
+ assertEquals("Foo", bm.readString());
+ }
+
+ public void testReadMultipleByteArrays() throws Exception
+ {
+ JMSStreamMessage bm = TestMessageHelper.newJMSStreamMessage();
+ byte[] bytes = {2, 3, 4};
+ bm.writeBytes(bytes);
+ bm.writeBytes(bytes);
+ bm.reset();
+ byte[] result = new byte[2];
+ int len = bm.readBytes(result);
+ assertEquals(2, len);
+ len = bm.readBytes(result);
+ assertEquals(1, len);
+ len = bm.readBytes(result);
+ assertEquals(2, len);
+ }
+
+ public void testEOFByte() throws Exception
+ {
+ try
+ {
+ JMSStreamMessage bm = TestMessageHelper.newJMSStreamMessage();
+ bm.writeByte((byte)1);
+ bm.reset();
+ bm.readByte();
+ // should throw
+ bm.readByte();
+ fail("expected exception did not occur");
+ }
+ catch (MessageEOFException m)
+ {
+ // ok
+ }
+ catch (Exception e)
+ {
+ fail("expected MessageEOFException, got " + e);
+ }
+ }
+
+ public void testEOFBoolean() throws Exception
+ {
+ try
+ {
+ JMSStreamMessage bm = TestMessageHelper.newJMSStreamMessage();
+ bm.writeBoolean(true);
+ bm.reset();
+ bm.readBoolean();
+ // should throw
+ bm.readBoolean();
+ fail("expected exception did not occur");
+ }
+ catch (MessageEOFException m)
+ {
+ // ok
+ }
+ catch (Exception e)
+ {
+ fail("expected MessageEOFException, got " + e);
+ }
+ }
+
+ public void testEOFChar() throws Exception
+ {
+ try
+ {
+ JMSStreamMessage bm = TestMessageHelper.newJMSStreamMessage();
+ bm.writeChar('A');
+ bm.reset();
+ bm.readChar();
+ // should throw
+ bm.readChar();
+ fail("expected exception did not occur");
+ }
+ catch (MessageEOFException m)
+ {
+ // ok
+ }
+ catch (Exception e)
+ {
+ fail("expected MessageEOFException, got " + e);
+ }
+ }
+
+ public void testEOFDouble() throws Exception
+ {
+ try
+ {
+ JMSStreamMessage bm = TestMessageHelper.newJMSStreamMessage();
+ bm.writeDouble(1.3d);
+ bm.reset();
+ bm.readDouble();
+ // should throw
+ bm.readDouble();
+ fail("expected exception did not occur");
+ }
+ catch (MessageEOFException m)
+ {
+ // ok
+ }
+ catch (Exception e)
+ {
+ fail("expected MessageEOFException, got " + e);
+ }
+ }
+
+ public void testEOFFloat() throws Exception
+ {
+ try
+ {
+ JMSStreamMessage bm = TestMessageHelper.newJMSStreamMessage();
+ bm.writeFloat(1.3f);
+ bm.reset();
+ bm.readFloat();
+ // should throw
+ bm.readFloat();
+ fail("expected exception did not occur");
+ }
+ catch (MessageEOFException m)
+ {
+ // ok
+ }
+ catch (Exception e)
+ {
+ fail("expected MessageEOFException, got " + e);
+ }
+ }
+
+ public void testEOFInt() throws Exception
+ {
+ try
+ {
+ JMSStreamMessage bm = TestMessageHelper.newJMSStreamMessage();
+ bm.writeInt(99);
+ bm.reset();
+ bm.readInt();
+ // should throw
+ bm.readInt();
+ fail("expected exception did not occur");
+ }
+ catch (MessageEOFException m)
+ {
+ // ok
+ }
+ catch (Exception e)
+ {
+ fail("expected MessageEOFException, got " + e);
+ }
+ }
+
+ public void testEOFLong() throws Exception
+ {
+ try
+ {
+ JMSStreamMessage bm = TestMessageHelper.newJMSStreamMessage();
+ bm.writeLong(4L);
+ bm.reset();
+ bm.readLong();
+ // should throw
+ bm.readLong();
+ fail("expected exception did not occur");
+ }
+ catch (MessageEOFException m)
+ {
+ // ok
+ }
+ catch (Exception e)
+ {
+ fail("expected MessageEOFException, got " + e);
+ }
+ }
+
+ public void testEOFShort() throws Exception
+ {
+ try
+ {
+ JMSStreamMessage bm = TestMessageHelper.newJMSStreamMessage();
+ bm.writeShort((short)4);
+ bm.reset();
+ bm.readShort();
+ // should throw
+ bm.readShort();
+ fail("expected exception did not occur");
+ }
+ catch (MessageEOFException m)
+ {
+ // ok
+ }
+ catch (Exception e)
+ {
+ fail("expected MessageEOFException, got " + e);
+ }
+ }
+
+ public void testToBodyStringWithNull() throws Exception
+ {
+ JMSStreamMessage bm = TestMessageHelper.newJMSStreamMessage();
+ bm.reset();
+ String result = bm.toBodyString();
+ assertNull(result);
+ }
+
+ private void checkConversionsFail(StreamMessage sm, int[] conversions) throws JMSException
+ {
+ for (int conversion : conversions)
+ {
+ try
+ {
+ switch (conversion)
+ {
+ case 0:
+ sm.readBoolean();
+ break;
+ case 1:
+ sm.readByte();
+ break;
+ case 2:
+ sm.readShort();
+ break;
+ case 3:
+ sm.readChar();
+ break;
+ case 4:
+ sm.readInt();
+ break;
+ case 5:
+ sm.readLong();
+ break;
+ case 6:
+ sm.readFloat();
+ break;
+ case 7:
+ sm.readDouble();
+ break;
+ case 8:
+ sm.readString();
+ break;
+ case 9:
+ sm.readBytes(new byte[3]);
+ break;
+ }
+ fail("MessageFormatException was not thrown");
+ }
+ catch (MessageFormatException e)
+ {
+ // PASS
+ }
+ sm.reset();
+ }
+ }
+ public void testBooleanConversions() throws Exception
+ {
+ JMSStreamMessage bm = TestMessageHelper.newJMSStreamMessage();
+ bm.writeBoolean(true);
+ bm.reset();
+ String result = bm.readString();
+ assertEquals("true", result);
+ bm.reset();
+ checkConversionsFail(bm, new int[]{1,2,3,4,5,6,7,9});
+ }
+
+ public void testByteConversions() throws Exception
+ {
+ JMSStreamMessage bm = TestMessageHelper.newJMSStreamMessage();
+ bm.writeByte((byte) 43);
+ bm.reset();
+ assertEquals(43, bm.readShort());
+ bm.reset();
+ assertEquals(43, bm.readInt());
+ bm.reset();
+ assertEquals(43, bm.readLong());
+ bm.reset();
+ String result = bm.readString();
+ assertEquals("43", result);
+ bm.reset();
+ checkConversionsFail(bm, new int[]{0, 3, 6, 7, 9});
+ }
+
+ public void testShortConversions() throws Exception
+ {
+ JMSStreamMessage bm = TestMessageHelper.newJMSStreamMessage();
+ bm.writeShort((short) 87);
+ bm.reset();
+ assertEquals(87, bm.readInt());
+ bm.reset();
+ assertEquals(87, bm.readLong());
+ bm.reset();
+ assertEquals("87", bm.readString());
+ bm.reset();
+ checkConversionsFail(bm, new int[]{0, 1, 3, 6, 7, });
+ }
+
+ public void testCharConversions() throws Exception
+ {
+ JMSStreamMessage bm = TestMessageHelper.newJMSStreamMessage();
+ bm.writeChar('d');
+ bm.reset();
+ assertEquals("d", bm.readString());
+ bm.reset();
+ checkConversionsFail(bm, new int[]{0, 1, 2, 4, 5, 6, 7, 9});
+ }
+
+ public void testIntConversions() throws Exception
+ {
+ JMSStreamMessage bm = TestMessageHelper.newJMSStreamMessage();
+ bm.writeInt(167);
+ bm.reset();
+ assertEquals(167, bm.readLong());
+ bm.reset();
+ assertEquals("167", bm.readString());
+ bm.reset();
+ checkConversionsFail(bm, new int[]{0, 1, 2, 3, 6, 7, 9});
+ }
+
+ public void testLongConversions() throws Exception
+ {
+ JMSStreamMessage bm = TestMessageHelper.newJMSStreamMessage();
+ bm.writeLong(1678);
+ bm.reset();
+ assertEquals("1678", bm.readString());
+ bm.reset();
+ checkConversionsFail(bm, new int[]{0, 1, 2, 3, 4, 6, 7, 9});
+ }
+
+ public void testFloatConversions() throws Exception
+ {
+ JMSStreamMessage bm = TestMessageHelper.newJMSStreamMessage();
+ bm.writeFloat(6.2f);
+ bm.reset();
+ assertEquals(6.2d, bm.readDouble(), 0.01);
+ bm.reset();
+ assertEquals("6.2", bm.readString());
+ bm.reset();
+ checkConversionsFail(bm, new int[]{0, 1, 2, 3, 4, 5, 9});
+ }
+
+ public void testDoubleConversions() throws Exception
+ {
+ JMSStreamMessage bm = TestMessageHelper.newJMSStreamMessage();
+ bm.writeDouble(88.35d);
+ bm.reset();
+ assertEquals("88.35", bm.readString());
+ bm.reset();
+ checkConversionsFail(bm, new int[]{0, 1, 2, 3, 4, 5, 6, 9});
+ }
+
+ public void testStringConversions() throws Exception
+ {
+ JMSStreamMessage bm = TestMessageHelper.newJMSStreamMessage();
+ bm.writeString("true");
+ bm.reset();
+ assertEquals(true, bm.readBoolean());
+ bm = TestMessageHelper.newJMSStreamMessage();
+ bm.writeString("2");
+ bm.reset();
+ assertEquals((byte)2, bm.readByte());
+ bm.reset();
+ assertEquals((short)2, bm.readShort());
+ bm.reset();
+ assertEquals(2, bm.readInt());
+ bm.reset();
+ assertEquals((long)2, bm.readLong());
+ bm = TestMessageHelper.newJMSStreamMessage();
+ bm.writeString("5.7");
+ bm.reset();
+ assertEquals(5.7f, bm.readFloat());
+ bm.reset();
+ assertEquals(5.7d, bm.readDouble());
+ }
+
+ public void testNulls() throws Exception
+ {
+ JMSStreamMessage bm = TestMessageHelper.newJMSStreamMessage();
+ bm.writeString(null);
+ bm.writeObject(null);
+ bm.reset();
+ assertNull(bm.readObject());
+ assertNull(bm.readObject());
+ }
+
+ public static junit.framework.Test suite()
+ {
+ return new junit.framework.TestSuite(StreamMessageTest.class);
+ }
+}
diff --git a/Final/java/client/src/test/java/org/apache/qpid/test/unit/client/message/TextMessageTest.java b/Final/java/client/src/test/java/org/apache/qpid/test/unit/client/message/TextMessageTest.java
new file mode 100644
index 0000000000..30f3b0b4eb
--- /dev/null
+++ b/Final/java/client/src/test/java/org/apache/qpid/test/unit/client/message/TextMessageTest.java
@@ -0,0 +1,300 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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.message;
+
+import javax.jms.JMSException;
+
+import junit.framework.Assert;
+import junit.framework.TestCase;
+
+import org.apache.qpid.client.message.JMSMapMessage;
+import org.apache.qpid.client.message.JMSTextMessage;
+import org.apache.qpid.client.message.TestMessageHelper;
+
+public class TextMessageTest extends TestCase
+{
+ public void testTextOnConstruction() throws Exception
+ {
+ JMSTextMessage tm = TestMessageHelper.newJMSTextMessage();
+ tm.setText("pies");
+ String val = tm.getText();
+ assertEquals(val, "pies");
+ }
+
+ public void testClearBody() throws Exception
+ {
+ JMSTextMessage tm = TestMessageHelper.newJMSTextMessage();
+ tm.setText("pies");
+ tm.clearBody();
+ String val = tm.getText();
+ assertNull(val);
+ tm.setText("Banana");
+ val = tm.getText();
+ assertEquals(val, "Banana");
+ }
+
+
+ public void testBooleanPropertyLookup()
+ {
+ try
+ {
+ JMSTextMessage tm = TestMessageHelper.newJMSTextMessage();
+
+ tm.setBooleanProperty("value", true);
+ Assert.assertEquals(true, tm.getBooleanProperty("value"));
+ Assert.assertEquals("true", tm.getStringProperty("value"));
+ }
+ catch (JMSException e)
+ {
+ Assert.fail("JMSException received." + e);
+ }
+ }
+
+ public void testBytePropertyLookup()
+ {
+ try
+ {
+ JMSMapMessage mm = TestMessageHelper.newJMSMapMessage();
+ mm.setByteProperty("value", Byte.MAX_VALUE);
+
+ Assert.assertEquals(Byte.MAX_VALUE, mm.getByteProperty("value"));
+ Assert.assertEquals((short) Byte.MAX_VALUE, mm.getShortProperty("value"));
+ Assert.assertEquals(Byte.MAX_VALUE, mm.getIntProperty("value"));
+ Assert.assertEquals((long) Byte.MAX_VALUE, mm.getLongProperty("value"));
+ Assert.assertEquals("" + Byte.MAX_VALUE, mm.getStringProperty("value"));
+
+ }
+ catch (JMSException e)
+ {
+ Assert.fail("JMSException received." + e);
+ }
+ }
+
+ public void testShortPropertyLookup()
+ {
+ try
+ {
+ JMSMapMessage mm = TestMessageHelper.newJMSMapMessage();
+ mm.setShortProperty("value", Short.MAX_VALUE);
+ Assert.assertEquals(Short.MAX_VALUE, mm.getShortProperty("value"));
+ Assert.assertEquals((int) Short.MAX_VALUE, mm.getIntProperty("value"));
+ Assert.assertEquals((long) Short.MAX_VALUE, mm.getLongProperty("value"));
+ Assert.assertEquals("" + Short.MAX_VALUE, mm.getStringProperty("value"));
+ }
+ catch (JMSException e)
+ {
+ Assert.fail("JMSException received." + e);
+ }
+ }
+
+ public void testDoublePropertyLookup()
+ {
+ try
+ {
+ JMSMapMessage mm = TestMessageHelper.newJMSMapMessage();
+ mm.setDoubleProperty("value", Double.MAX_VALUE);
+ Assert.assertEquals(Double.MAX_VALUE, mm.getDoubleProperty("value"));
+ Assert.assertEquals("" + Double.MAX_VALUE, mm.getStringProperty("value"));
+ }
+ catch (JMSException e)
+ {
+ Assert.fail("JMSException received." + e);
+ }
+ }
+
+ public void testFloatPropertyLookup()
+ {
+ try
+ {
+ JMSMapMessage mm = TestMessageHelper.newJMSMapMessage();
+ mm.setFloatProperty("value", Float.MAX_VALUE);
+ Assert.assertEquals(Float.MAX_VALUE, mm.getFloatProperty("value"));
+ Assert.assertEquals((double) Float.MAX_VALUE, mm.getDoubleProperty("value"));
+ Assert.assertEquals("" + Float.MAX_VALUE, mm.getStringProperty("value"));
+ }
+ catch (JMSException e)
+ {
+ Assert.fail("JMSException received." + e);
+ }
+ }
+
+ public void testIntPropertyLookup()
+ {
+ try
+ {
+ JMSMapMessage mm = TestMessageHelper.newJMSMapMessage();
+ mm.setIntProperty("value", Integer.MAX_VALUE);
+ Assert.assertEquals(Integer.MAX_VALUE, mm.getIntProperty("value"));
+ Assert.assertEquals((long) Integer.MAX_VALUE, mm.getLongProperty("value"));
+ Assert.assertEquals("" + Integer.MAX_VALUE, mm.getStringProperty("value"));
+ }
+ catch (JMSException e)
+ {
+ Assert.fail("JMSException received." + e);
+ }
+ }
+
+ public void testLongPropertyLookup()
+ {
+ try
+ {
+ JMSMapMessage mm = TestMessageHelper.newJMSMapMessage();
+ mm.setLongProperty("value", Long.MAX_VALUE);
+ Assert.assertEquals(Long.MAX_VALUE, mm.getLongProperty("value"));
+ Assert.assertEquals("" + Long.MAX_VALUE, mm.getStringProperty("value"));
+ }
+ catch (JMSException e)
+ {
+ Assert.fail("JMSException received." + e);
+ }
+ }
+
+
+ // Failed Lookups
+
+ public void testFailedBooleanPropertyLookup()
+ {
+ try
+ {
+ JMSMapMessage mm = TestMessageHelper.newJMSMapMessage();
+ Assert.assertEquals(false, mm.getBooleanProperty("int"));
+ }
+ catch (JMSException e)
+ {
+ Assert.fail("JMSException received." + e);
+ }
+ }
+
+ public void testFailedBytePropertyLookup()
+ {
+ try
+ {
+ JMSMapMessage mm = TestMessageHelper.newJMSMapMessage();
+ mm.getByteProperty("random");
+ Assert.fail("NumberFormatException expected");
+ }
+ catch (NumberFormatException e)
+ {
+ //normal execution
+ }
+ catch (JMSException e)
+ {
+ Assert.fail("JMSException received:" + e);
+ }
+
+ }
+
+ public void testFailedDoublePropertyLookup()
+ {
+ try
+ {
+ JMSMapMessage mm = TestMessageHelper.newJMSMapMessage();
+ mm.getDoubleProperty("random");
+ Assert.fail("NullPointerException should be received.");
+ }
+ catch (NullPointerException e)
+ {
+ //normal execution
+ }
+ catch (JMSException e)
+ {
+ Assert.fail("JMSException received:" + e);
+ }
+ }
+
+ public void testFailedFloatPropertyLookup()
+ {
+ try
+ {
+ JMSMapMessage mm = TestMessageHelper.newJMSMapMessage();
+ mm.getFloatProperty("random");
+ Assert.fail("NullPointerException should be received.");
+ }
+ catch (NullPointerException e)
+ {
+ //normal execution
+ }
+ catch (JMSException e)
+ {
+ Assert.fail("JMSException received:" + e);
+ }
+ }
+
+ public void testFailedIntPropertyLookup()
+ {
+ try
+ {
+ JMSMapMessage mm = TestMessageHelper.newJMSMapMessage();
+ mm.getIntProperty("random");
+ Assert.fail("NumberFormatException should be received.");
+ }
+ catch (NumberFormatException e)
+ {
+ //normal execution
+ }
+ catch (JMSException e)
+ {
+ Assert.fail("JMSException received:" + e);
+ }
+ }
+
+ public void testFailedLongPropertyLookup()
+ {
+ try
+ {
+ JMSMapMessage mm = TestMessageHelper.newJMSMapMessage();
+ mm.getLongProperty("random");
+ Assert.fail("NumberFormatException should be received.");
+ }
+ catch (NumberFormatException e)
+ {
+ //normal execution
+ }
+ catch (JMSException e)
+ {
+ Assert.fail("JMSException received:" + e);
+ }
+ }
+
+ public void testFailedShortPropertyLookup()
+ {
+ try
+ {
+ JMSMapMessage mm = TestMessageHelper.newJMSMapMessage();
+ mm.getShortProperty("random");
+ Assert.fail("NumberFormatException should be received.");
+ }
+ catch (NumberFormatException e)
+ {
+ //normal execution
+ }
+ catch (JMSException e)
+ {
+ Assert.fail("JMSException received:" + e);
+ }
+ }
+
+
+ public static junit.framework.Test suite()
+ {
+ return new junit.framework.TestSuite(TextMessageTest.class);
+ }
+}
diff --git a/Final/java/client/src/test/java/org/apache/qpid/test/unit/client/protocol/TestIoSession.java b/Final/java/client/src/test/java/org/apache/qpid/test/unit/client/protocol/TestIoSession.java
new file mode 100644
index 0000000000..d14e0b771f
--- /dev/null
+++ b/Final/java/client/src/test/java/org/apache/qpid/test/unit/client/protocol/TestIoSession.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.test.unit.client.protocol;
+
+import java.net.InetSocketAddress;
+import java.net.SocketAddress;
+
+import org.apache.mina.common.IoFilterChain;
+import org.apache.mina.common.IoHandler;
+import org.apache.mina.common.IoService;
+import org.apache.mina.common.IoServiceConfig;
+import org.apache.mina.common.IoSessionConfig;
+import org.apache.mina.common.TransportType;
+import org.apache.mina.common.support.BaseIoSession;
+
+public class TestIoSession extends BaseIoSession {
+
+ private String _stringLocalAddress;
+ private int _localPort;
+
+ public SocketAddress getLocalAddress()
+ {
+ //create a new address for testing purposes using member variables
+ return new InetSocketAddress(_stringLocalAddress,_localPort);
+ }
+
+ protected void updateTrafficMask() {
+ //dummy
+ }
+
+ public IoService getService() {
+ return null;
+ }
+
+ public IoServiceConfig getServiceConfig() {
+ return null;
+ }
+
+ public IoHandler getHandler() {
+ return null;
+ }
+
+ public IoSessionConfig getConfig() {
+ return null;
+ }
+
+ public IoFilterChain getFilterChain() {
+ return null;
+ }
+
+ public TransportType getTransportType() {
+ return null;
+ }
+
+ public SocketAddress getRemoteAddress() {
+ return null;
+ }
+
+ public SocketAddress getServiceAddress() {
+ return null;
+ }
+
+ public int getScheduledWriteRequests() {
+ return 0;
+ }
+
+ public int getScheduledWriteBytes() {
+ return 0;
+ }
+
+ public String getStringLocalAddress() {
+ return _stringLocalAddress;
+ }
+
+ public void setStringLocalAddress(String _stringLocalAddress) {
+ this._stringLocalAddress = _stringLocalAddress;
+ }
+
+ public int getLocalPort() {
+ return _localPort;
+ }
+
+ public void setLocalPort(int _localPort) {
+ this._localPort = _localPort;
+ }
+}
diff --git a/Final/java/client/src/test/java/org/apache/qpid/test/unit/client/temporaryqueue/TemporaryQueueTest.java b/Final/java/client/src/test/java/org/apache/qpid/test/unit/client/temporaryqueue/TemporaryQueueTest.java
new file mode 100644
index 0000000000..241c9177a8
--- /dev/null
+++ b/Final/java/client/src/test/java/org/apache/qpid/test/unit/client/temporaryqueue/TemporaryQueueTest.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.test.unit.client.temporaryqueue;
+
+import javax.jms.Connection;
+import javax.jms.JMSException;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageProducer;
+import javax.jms.Session;
+import javax.jms.TemporaryQueue;
+import javax.jms.TextMessage;
+import javax.jms.Queue;
+
+import junit.framework.TestCase;
+import junit.framework.Assert;
+
+import org.apache.qpid.AMQException;
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.client.AMQQueue;
+import org.apache.qpid.client.transport.TransportConnection;
+import org.apache.qpid.url.URLSyntaxException;
+
+import java.util.List;
+import java.util.LinkedList;
+
+public class TemporaryQueueTest extends TestCase
+{
+
+ String _broker = "vm://:1";
+
+
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+ TransportConnection.createVMBroker(1);
+ }
+
+ protected void tearDown() throws Exception
+ {
+ TransportConnection.killAllVMBrokers();
+ }
+
+ protected Connection createConnection() throws AMQException, URLSyntaxException
+ {
+ return new AMQConnection(_broker, "guest", "guest",
+ "fred", "test");
+ }
+
+ public void testTempoaryQueue() throws Exception
+ {
+ Connection conn = createConnection();
+ Session session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ TemporaryQueue queue = session.createTemporaryQueue();
+ assertNotNull(queue);
+ MessageProducer producer = session.createProducer(queue);
+ MessageConsumer consumer = session.createConsumer(queue);
+ conn.start();
+ producer.send(session.createTextMessage("hello"));
+ TextMessage tm = (TextMessage) consumer.receive(2000);
+ assertNotNull(tm);
+ assertEquals("hello", tm.getText());
+
+ try
+ {
+ queue.delete();
+ fail("Expected JMSException : should not be able to delete while there are active consumers");
+ }
+ catch (JMSException je)
+ {
+ ; //pass
+ }
+
+ consumer.close();
+
+ try
+ {
+ queue.delete();
+ }
+ catch (JMSException je)
+ {
+ fail("Unexpected Exception: " + je.getMessage());
+ }
+
+ conn.close();
+ }
+
+ public void tUniqueness() throws JMSException, AMQException, URLSyntaxException
+ {
+ int numProcs = Runtime.getRuntime().availableProcessors();
+ final int threadsProc = 5;
+
+ runUniqueness(1, 10);
+ runUniqueness(numProcs * threadsProc, 10);
+ runUniqueness(numProcs * threadsProc, 100);
+ runUniqueness(numProcs * threadsProc, 500);
+ }
+
+ void runUniqueness(int makers, int queues) throws JMSException, AMQException, URLSyntaxException
+ {
+ Connection connection = createConnection();
+
+ Session session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE);
+
+ List<TempQueueMaker> tqList = new LinkedList<TempQueueMaker>();
+
+ //Create Makers
+ for (int m = 0; m < makers; m++)
+ {
+ tqList.add(new TempQueueMaker(session, queues));
+ }
+
+
+ List<Thread> threadList = new LinkedList<Thread>();
+
+ //Create Makers
+ for (TempQueueMaker maker : tqList)
+ {
+ threadList.add(new Thread(maker));
+ }
+
+ //Start threads
+ for (Thread thread : threadList)
+ {
+ thread.start();
+ }
+
+ // Join Threads
+ for (Thread thread : threadList)
+ {
+ try
+ {
+ thread.join();
+ }
+ catch (InterruptedException e)
+ {
+ fail("Couldn't correctly join threads");
+ }
+ }
+
+
+ List<AMQQueue> list = new LinkedList<AMQQueue>();
+
+ // Test values
+ for (TempQueueMaker maker : tqList)
+ {
+ check(maker, list);
+ }
+
+ Assert.assertEquals("Not enough queues made.", makers * queues, list.size());
+
+ connection.close();
+ }
+
+ private void check(TempQueueMaker tq, List<AMQQueue> list)
+ {
+ for (AMQQueue q : tq.getList())
+ {
+ if (list.contains(q))
+ {
+ fail(q + " already exists.");
+ }
+ else
+ {
+ list.add(q);
+ }
+ }
+ }
+
+
+ class TempQueueMaker implements Runnable
+ {
+ List<AMQQueue> _queues;
+ Session _session;
+ private int _count;
+
+
+ TempQueueMaker(Session session, int queues) throws JMSException
+ {
+ _queues = new LinkedList<AMQQueue>();
+
+ _count = queues;
+
+ _session = session;
+ }
+
+ public void run()
+ {
+ int i = 0;
+ try
+ {
+ for (; i < _count; i++)
+ {
+ _queues.add((AMQQueue) _session.createTemporaryQueue());
+ }
+ }
+ catch (JMSException jmse)
+ {
+ //stop
+ }
+ }
+
+ List<AMQQueue> getList()
+ {
+ return _queues;
+ }
+ }
+
+
+ public static junit.framework.Test suite()
+ {
+ return new junit.framework.TestSuite(TemporaryQueueTest.class);
+ }
+}
diff --git a/Final/java/client/src/test/java/org/apache/qpid/test/unit/close/CloseBeforeAckTest.java b/Final/java/client/src/test/java/org/apache/qpid/test/unit/close/CloseBeforeAckTest.java
new file mode 100644
index 0000000000..5a61480f6a
--- /dev/null
+++ b/Final/java/client/src/test/java/org/apache/qpid/test/unit/close/CloseBeforeAckTest.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.test.unit.close;
+
+import junit.framework.Assert;
+import junit.framework.TestCase;
+
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.client.transport.TransportConnection;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import uk.co.thebadgerset.junit.concurrency.TestRunnable;
+import uk.co.thebadgerset.junit.concurrency.ThreadTestCoordinator;
+
+import javax.jms.Connection;
+import javax.jms.Message;
+import javax.jms.MessageListener;
+import javax.jms.Session;
+
+/**
+ * This test forces the situation where a session is closed whilst a message consumer is still in its onMessage method.
+ * Running in AUTO_ACK mode, the close call ought to wait until the onMessage method completes, and the ack is sent
+ * before closing the connection.
+ *
+ * <p><table id="crc"><caption>CRC Card</caption> <tr><th> Responsibilities <th> Collaborations <tr><td> Check that
+ * closing a connection whilst handling a message, blocks till completion of the handler. </table>
+ */
+public class CloseBeforeAckTest extends TestCase
+{
+ private static final Logger log = LoggerFactory.getLogger(CloseBeforeAckTest.class);
+
+ Connection connection;
+ Session session;
+ public static final String TEST_QUEUE_NAME = "TestQueue";
+ private int TEST_COUNT = 25;
+
+ class TestThread1 extends TestRunnable implements MessageListener
+ {
+ public void runWithExceptions() throws Exception
+ {
+ // Set this up to listen for message on the test session.
+ session.createConsumer(session.createQueue(TEST_QUEUE_NAME)).setMessageListener(this);
+ }
+
+ public void onMessage(Message message)
+ {
+ // Give thread 2 permission to close the session.
+ allow(new int[] { 1 });
+
+ // Wait until thread 2 has closed the connection, or is blocked waiting for this to complete.
+ waitFor(new int[] { 1 }, true);
+ }
+ }
+
+ TestThread1 testThread1 = new TestThread1();
+
+ TestRunnable testThread2 =
+ new TestRunnable()
+ {
+ public void runWithExceptions() throws Exception
+ {
+ // Send a message to be picked up by thread 1.
+ session.createProducer(null).send(session.createQueue(TEST_QUEUE_NAME),
+ session.createTextMessage("Hi there thread 1!"));
+
+ // Wait for thread 1 to pick up the message and give permission to continue.
+ waitFor(new int[] { 0 }, false);
+
+ // Close the connection.
+ session.close();
+
+ // Allow thread 1 to continue to completion, if it is erronously still waiting.
+ allow(new int[] { 1 });
+ }
+ };
+
+ public void testCloseBeforeAutoAck_QPID_397() throws Exception
+ {
+ // Create a session in auto acknowledge mode. This problem shows up in auto acknowledge if the client acks
+ // message at the end of the onMessage method, after a close has been sent.
+ session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ ThreadTestCoordinator tt = new ThreadTestCoordinator(2);
+
+ tt.addTestThread(testThread1, 0);
+ tt.addTestThread(testThread2, 1);
+ tt.setDeadlockTimeout(500);
+ tt.run();
+
+ String errorMessage = tt.joinAndRetrieveMessages();
+
+ // Print any error messages or exceptions.
+ log.debug(errorMessage);
+
+ if (!tt.getExceptions().isEmpty())
+ {
+ for (Exception e : tt.getExceptions())
+ {
+ log.debug("Exception thrown during test thread: ", e);
+ }
+ }
+
+ Assert.assertTrue(errorMessage, "".equals(errorMessage));
+ }
+
+ public void closeBeforeAutoAckManyTimes() throws Exception
+ {
+ for (int i = 0; i < TEST_COUNT; i++)
+ {
+ testCloseBeforeAutoAck_QPID_397();
+ }
+ }
+
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+ TransportConnection.createVMBroker(1);
+
+ connection = new AMQConnection("vm://:1", "guest", "guest", getName(), "test");
+ }
+
+ protected void tearDown() throws Exception
+ {
+ super.tearDown();
+ TransportConnection.killVMBroker(1);
+ }
+}
diff --git a/Final/java/client/src/test/java/org/apache/qpid/test/unit/close/MessageRequeueTest.java b/Final/java/client/src/test/java/org/apache/qpid/test/unit/close/MessageRequeueTest.java
new file mode 100644
index 0000000000..bf8802c803
--- /dev/null
+++ b/Final/java/client/src/test/java/org/apache/qpid/test/unit/close/MessageRequeueTest.java
@@ -0,0 +1,389 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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 junit.framework.TestCase;
+
+import org.apache.qpid.AMQException;
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.client.message.AbstractJMSMessage;
+import org.apache.qpid.client.transport.TransportConnection;
+import org.apache.qpid.testutil.QpidClientConnection;
+import org.apache.qpid.url.URLSyntaxException;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.Queue;
+import javax.jms.Session;
+
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.UUID;
+
+public class MessageRequeueTest extends TestCase
+{
+ private static final Logger _logger = LoggerFactory.getLogger(MessageRequeueTest.class);
+
+ protected static AtomicInteger consumerIds = new AtomicInteger(0);
+ protected final Integer numTestMessages = 150;
+
+ protected final int consumeTimeout = 3000;
+
+
+ protected String payload = "Message:";
+
+ protected final String BROKER = "vm://:1";
+ private boolean testReception = true;
+
+ private long[] receieved = new long[numTestMessages + 1];
+ private boolean passed = false;
+
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+ TransportConnection.createVMBroker(1);
+
+
+ }
+
+ protected void tearDown() throws Exception
+ {
+ super.tearDown();
+
+
+ TransportConnection.killVMBroker(1);
+ }
+
+ /**
+ * multiple consumers
+ *
+ * @throws javax.jms.JMSException if a JMS problem occurs
+ * @throws InterruptedException on timeout
+ */
+ public void testDrain() throws JMSException, InterruptedException
+ {
+ final String queueName = "direct://amq.direct//queue" + UUID.randomUUID().toString();
+
+ QpidClientConnection conn = new QpidClientConnection(BROKER);
+
+ conn.connect();
+ // clear queue
+ conn.consume(queueName, consumeTimeout);
+ // load test data
+ _logger.info("creating test data, " + numTestMessages + " messages");
+ conn.put(queueName, payload, numTestMessages);
+ // close this connection
+ conn.disconnect();
+
+ conn = new QpidClientConnection(BROKER);
+
+ conn.connect();
+
+ _logger.info("consuming queue " + queueName);
+ Queue q = conn.getSession().createQueue(queueName);
+
+ final MessageConsumer consumer = conn.getSession().createConsumer(q);
+ int messagesReceived = 0;
+
+ long[] messageLog = new long[numTestMessages + 1];
+
+ _logger.info("consuming...");
+ Message msg = consumer.receive(1000);
+ while (msg != null)
+ {
+ messagesReceived++;
+
+ long dt = ((AbstractJMSMessage) msg).getDeliveryTag();
+
+ int msgindex = msg.getIntProperty("index");
+ if (messageLog[msgindex] != 0)
+ {
+ _logger.error("Received Message(" + msgindex + ":" + ((AbstractJMSMessage) msg).getDeliveryTag()
+ + ") more than once.");
+ }
+
+ if (_logger.isInfoEnabled())
+ {
+ _logger.info("Received Message(" + System.identityHashCode(msgindex) + ") " + "DT:" + dt + "IN:" + msgindex);
+ }
+
+ if (dt == 0)
+ {
+ _logger.error("DT is zero for msg:" + msgindex);
+ }
+
+ messageLog[msgindex] = dt;
+
+ // get Next message
+ msg = consumer.receive(1000);
+ }
+
+ conn.getSession().commit();
+ consumer.close();
+ assertEquals("number of consumed messages does not match initial data", (int) numTestMessages, messagesReceived);
+
+ int index = 0;
+ StringBuilder list = new StringBuilder();
+ list.append("Failed to receive:");
+ int failed = 0;
+
+ for (long b : messageLog)
+ {
+ if ((b == 0) && (index != 0)) // delivery tag of zero shouldn't exist
+ {
+ _logger.error("Index: " + index + " was not received.");
+ list.append(" ");
+ list.append(index);
+ list.append(":");
+ list.append(b);
+ failed++;
+ }
+
+ index++;
+ }
+
+ assertEquals(list.toString(), 0, failed);
+ _logger.info("consumed: " + messagesReceived);
+ conn.disconnect();
+ passed = true;
+
+ }
+
+
+
+ /** multiple consumers
+ * Based on code subbmitted by client FT-304
+ */
+ public void testCompetingConsumers() throws JMSException, InterruptedException
+ {
+ final String queueName = "direct://amq.direct//queue" + UUID.randomUUID().toString();
+
+ QpidClientConnection conn = new QpidClientConnection(BROKER);
+
+ conn.connect();
+ // clear queue
+ conn.consume(queueName, consumeTimeout);
+ // load test data
+ _logger.info("creating test data, " + numTestMessages + " messages");
+ conn.put(queueName, payload, numTestMessages);
+ // close this connection
+ conn.disconnect();
+
+ Consumer c1 = new Consumer(queueName);
+ Consumer c2 = new Consumer(queueName);
+ Consumer c3 = new Consumer(queueName);
+ Consumer c4 = new Consumer(queueName);
+
+ Thread t1 = new Thread(c1);
+ Thread t2 = new Thread(c2);
+ Thread t3 = new Thread(c3);
+ Thread t4 = new Thread(c4);
+
+ t1.start();
+ t2.start();
+ t3.start();
+ t4.start();
+
+ try
+ {
+ t1.join();
+ t2.join();
+ t3.join();
+ t4.join();
+ }
+ catch (InterruptedException e)
+ {
+ fail("Uanble to join to Consumer theads");
+ }
+
+ _logger.info("consumer 1 count is " + c1.getCount());
+ _logger.info("consumer 2 count is " + c2.getCount());
+ _logger.info("consumer 3 count is " + c3.getCount());
+ _logger.info("consumer 4 count is " + c4.getCount());
+
+ Integer totalConsumed = c1.getCount() + c2.getCount() + c3.getCount() + c4.getCount();
+
+ // Check all messages were correctly delivered
+ int index = 0;
+ StringBuilder list = new StringBuilder();
+ list.append("Failed to receive:");
+ int failed = 0;
+
+ for (long b : receieved)
+ {
+ if ((b == 0) && (index != 0)) // delivery tag of zero shouldn't exist (and we don't have msg 0)
+ {
+ fail("Index: " + index + " was not received.");
+ list.append(" ");
+ list.append(index);
+ list.append(":");
+ list.append(b);
+ failed++;
+ }
+
+ index++;
+ }
+
+ assertEquals(list.toString() + "-" + numTestMessages + "-" + totalConsumed, 0, failed);
+ assertTrue("number of consumed messages does not match initial data: " + totalConsumed, numTestMessages <= totalConsumed);
+
+ }
+
+ class Consumer implements Runnable
+ {
+ private Integer count = 0;
+ private Integer id;
+ private final String _queueName;
+
+ public Consumer(String queueName)
+ {
+ _queueName = queueName;
+ id = consumerIds.addAndGet(1);
+ }
+
+ public void run()
+ {
+ try
+ {
+ _logger.info("consumer-" + id + ": starting");
+ QpidClientConnection conn = new QpidClientConnection(BROKER);
+
+ conn.connect();
+
+ _logger.info("consumer-" + id + ": connected, consuming...");
+ Message result;
+ do
+ {
+ result = conn.getNextMessage(_queueName, consumeTimeout);
+ if (result != null)
+ {
+
+ long dt = ((AbstractJMSMessage) result).getDeliveryTag();
+
+ if (testReception)
+ {
+ int msgindex = result.getIntProperty("index");
+ if (receieved[msgindex] != 0)
+ {
+ _logger.error("Received Message(" + msgindex + ":"
+ + ((AbstractJMSMessage) result).getDeliveryTag() + ") more than once.");
+ }
+
+ if (_logger.isInfoEnabled())
+ {
+ _logger.info("Received Message(" + System.identityHashCode(msgindex) + ") " + "DT:" + dt
+ + "IN:" + msgindex);
+ }
+
+ if (dt == 0)
+ {
+ _logger.error("DT is zero for msg:" + msgindex);
+ }
+
+ receieved[msgindex] = dt;
+ }
+
+ count++;
+ if ((count % 100) == 0)
+ {
+ _logger.info("consumer-" + id + ": got " + result + ", new count is " + count);
+ }
+ }
+ }
+ while (result != null);
+
+ _logger.info("consumer-" + id + ": complete");
+ conn.disconnect();
+
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ public Integer getCount()
+ {
+ return count;
+ }
+
+ public Integer getId()
+ {
+ return id;
+ }
+ }
+
+ public void testRequeue() throws JMSException, AMQException, URLSyntaxException, InterruptedException
+ {
+ final String queue = "direct://amq.direct//queue" + UUID.randomUUID().toString();
+
+ QpidClientConnection conn = new QpidClientConnection(BROKER);
+
+ conn.connect();
+ // clear queue
+ conn.consume(queue, consumeTimeout);
+ // load test data
+ _logger.info("creating test data, " + numTestMessages + " messages");
+ conn.put(queue, payload, numTestMessages);
+ // close this connection
+ conn.disconnect();
+
+ int run = 0;
+ // while (run < 10)
+ {
+ run++;
+
+ if (_logger.isInfoEnabled())
+ {
+ _logger.info("testRequeue run " + run);
+ }
+
+ String virtualHost = "/test";
+ String brokerlist = BROKER;
+ String brokerUrl = "amqp://guest:guest@" + virtualHost + "?brokerlist='" + brokerlist + "'";
+
+ AMQConnection amqConn = new AMQConnection(brokerUrl);
+ Session session = amqConn.createSession(false, Session.CLIENT_ACKNOWLEDGE);
+ Queue q = session.createQueue(queue);
+
+ _logger.debug("Create Consumer");
+ MessageConsumer consumer = session.createConsumer(q);
+
+ amqConn.start();
+
+ _logger.debug("Receiving msg");
+ Message msg = consumer.receive(2000);
+
+ assertNotNull("Message should not be null", msg);
+
+ // As we have not ack'd message will be requeued.
+ _logger.debug("Close Consumer");
+ consumer.close();
+
+ _logger.debug("Close Connection");
+ amqConn.close();
+ }
+ }
+
+}
diff --git a/Final/java/client/src/test/java/org/apache/qpid/test/unit/close/TopicPublisherCloseTest.java b/Final/java/client/src/test/java/org/apache/qpid/test/unit/close/TopicPublisherCloseTest.java
new file mode 100644
index 0000000000..5e2703d5a5
--- /dev/null
+++ b/Final/java/client/src/test/java/org/apache/qpid/test/unit/close/TopicPublisherCloseTest.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.unit.close;
+
+import javax.jms.Session;
+import javax.jms.Topic;
+import javax.jms.TopicPublisher;
+import javax.jms.TopicSession;
+
+import junit.framework.TestCase;
+
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.client.AMQTopic;
+import org.apache.qpid.client.transport.TransportConnection;
+
+/**
+ * @author Apache Software Foundation
+ */
+public class TopicPublisherCloseTest extends TestCase
+{
+
+ public String _connectionString = "vm://:1";
+
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+ TransportConnection.createVMBroker(1);
+ }
+
+
+ protected void tearDown() throws Exception
+ {
+ super.tearDown();
+ TransportConnection.killAllVMBrokers();
+ }
+
+ public void testAllMethodsThrowAfterConnectionClose() throws Exception
+ {
+ AMQConnection connection = new AMQConnection(_connectionString, "guest", "guest", "Client", "test");
+
+ Topic destination1 = new AMQTopic(connection, "t1");
+ TopicSession session1 = connection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE);
+ TopicPublisher pub = session1.createPublisher(destination1);
+ connection.close();
+ try
+ {
+ pub.getDeliveryMode();
+ fail("Expected exception not thrown");
+ }
+ catch (javax.jms.IllegalStateException e)
+ {
+ // PASS
+ }
+ }
+}
diff --git a/Final/java/client/src/test/java/org/apache/qpid/test/unit/message/JMSDestinationTest.java b/Final/java/client/src/test/java/org/apache/qpid/test/unit/message/JMSDestinationTest.java
new file mode 100644
index 0000000000..a1d9af558c
--- /dev/null
+++ b/Final/java/client/src/test/java/org/apache/qpid/test/unit/message/JMSDestinationTest.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.test.unit.message;
+
+import junit.framework.TestCase;
+
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.client.AMQQueue;
+import org.apache.qpid.client.AMQSession;
+import org.apache.qpid.client.transport.TransportConnection;
+import org.apache.qpid.framing.AMQShortString;
+
+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 TestCase
+{
+ private static final Logger _logger = LoggerFactory.getLogger(JMSDestinationTest.class);
+
+ public String _connectionString = "vm://:1";
+
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+ TransportConnection.createVMBroker(1);
+ }
+
+ protected void tearDown() throws Exception
+ {
+ super.tearDown();
+ TransportConnection.killAllVMBrokers();
+ }
+
+ public void testJMSDestination() throws Exception
+ {
+ AMQConnection con = new AMQConnection("vm://:1", "guest", "guest", "consumer1", "test");
+ 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 = new AMQConnection("vm://:1", "guest", "guest", "producer1", "test");
+ 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/Final/java/client/src/test/java/org/apache/qpid/test/unit/message/JMSPropertiesTest.java b/Final/java/client/src/test/java/org/apache/qpid/test/unit/message/JMSPropertiesTest.java
new file mode 100644
index 0000000000..3012909daa
--- /dev/null
+++ b/Final/java/client/src/test/java/org/apache/qpid/test/unit/message/JMSPropertiesTest.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.test.unit.message;
+
+import junit.framework.TestCase;
+
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.client.AMQQueue;
+import org.apache.qpid.client.AMQSession;
+import org.apache.qpid.client.message.NonQpidObjectMessage;
+import org.apache.qpid.client.transport.TransportConnection;
+import org.apache.qpid.framing.AMQShortString;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.jms.Destination;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageProducer;
+import javax.jms.ObjectMessage;
+import javax.jms.Queue;
+import javax.jms.Session;
+
+/**
+ * @author Apache Software Foundation
+ */
+public class JMSPropertiesTest extends TestCase
+{
+
+ private static final Logger _logger = LoggerFactory.getLogger(JMSPropertiesTest.class);
+
+ public String _connectionString = "vm://:1";
+
+ public static final String JMS_CORR_ID = "QPIDID_01";
+ public static final int JMS_DELIV_MODE = 1;
+ public static final String JMS_TYPE = "test.jms.type";
+
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+ TransportConnection.createVMBroker(1);
+ }
+
+ protected void tearDown() throws Exception
+ {
+ super.tearDown();
+ TransportConnection.killAllVMBrokers();
+ }
+
+ public void testJMSProperties() throws Exception
+ {
+ AMQConnection con = new AMQConnection("vm://:1", "guest", "guest", "consumer1", "test");
+ 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);
+
+ AMQConnection con2 = new AMQConnection("vm://:1", "guest", "guest", "producer1", "test");
+ Session producerSession = con2.createSession(false, Session.CLIENT_ACKNOWLEDGE);
+ MessageProducer producer = producerSession.createProducer(queue);
+ Destination JMS_REPLY_TO = new AMQQueue(con2, "my.replyto");
+ // create a test message to send
+ ObjectMessage sentMsg = new NonQpidObjectMessage();
+ sentMsg.setJMSCorrelationID(JMS_CORR_ID);
+ sentMsg.setJMSDeliveryMode(JMS_DELIV_MODE);
+ sentMsg.setJMSType(JMS_TYPE);
+ sentMsg.setJMSReplyTo(JMS_REPLY_TO);
+
+ // send it
+ producer.send(sentMsg);
+
+ con2.close();
+
+ con.start();
+
+ // get message and check JMS properties
+ ObjectMessage rm = (ObjectMessage) consumer.receive();
+ assertNotNull(rm);
+
+ assertEquals("JMS Correlation ID mismatch", sentMsg.getJMSCorrelationID(), rm.getJMSCorrelationID());
+ // TODO: Commented out as always overwritten by send delivery mode value - prob should not set in conversion
+ // assertEquals("JMS Delivery Mode mismatch",sentMsg.getJMSDeliveryMode(),rm.getJMSDeliveryMode());
+ assertEquals("JMS Type mismatch", sentMsg.getJMSType(), rm.getJMSType());
+ assertEquals("JMS Reply To mismatch", sentMsg.getJMSReplyTo(), rm.getJMSReplyTo());
+
+ con.close();
+ }
+
+}
diff --git a/Final/java/client/src/test/java/org/apache/qpid/test/unit/message/MessageConverterTest.java b/Final/java/client/src/test/java/org/apache/qpid/test/unit/message/MessageConverterTest.java
new file mode 100644
index 0000000000..fd425b9930
--- /dev/null
+++ b/Final/java/client/src/test/java/org/apache/qpid/test/unit/message/MessageConverterTest.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.test.unit.message;
+
+import javax.jms.Destination;
+import javax.jms.JMSException;
+import javax.jms.MapMessage;
+import javax.jms.Message;
+import javax.jms.TextMessage;
+
+import junit.framework.TestCase;
+
+import org.apache.qpid.client.AMQQueue;
+import org.apache.qpid.client.message.AbstractJMSMessage;
+import org.apache.qpid.client.message.JMSMapMessage;
+import org.apache.qpid.client.message.JMSTextMessage;
+import org.apache.qpid.client.message.MessageConverter;
+import org.apache.qpid.exchange.ExchangeDefaults;
+
+
+public class MessageConverterTest extends TestCase
+{
+
+ public static final String JMS_CORR_ID = "QPIDID_01";
+ public static final int JMS_DELIV_MODE = 1;
+ public static final String JMS_TYPE = "test.jms.type";
+ public static final Destination JMS_REPLY_TO = new AMQQueue(ExchangeDefaults.DIRECT_EXCHANGE_NAME,"my.replyto");
+
+ protected JMSTextMessage testTextMessage;
+
+ protected JMSMapMessage testMapMessage;
+
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+ testTextMessage = new JMSTextMessage();
+
+ //Set Message Text
+ testTextMessage.setText("testTextMessage text");
+ setMessageProperties(testTextMessage);
+
+ testMapMessage = new JMSMapMessage();
+ testMapMessage.setString("testMapString", "testMapStringValue");
+ testMapMessage.setDouble("testMapDouble", Double.MAX_VALUE);
+ }
+
+ public void testSetProperties() throws Exception
+ {
+ AbstractJMSMessage newMessage = new MessageConverter((TextMessage) testTextMessage).getConvertedMessage();
+ mesagePropertiesTest(testTextMessage, newMessage);
+ }
+
+ public void testJMSTextMessageConversion() throws Exception
+ {
+ AbstractJMSMessage newMessage = new MessageConverter((TextMessage) testTextMessage).getConvertedMessage();
+ assertEquals("Converted message text mismatch", ((JMSTextMessage) newMessage).getText(), testTextMessage.getText());
+ }
+
+ public void testJMSMapMessageConversion() throws Exception
+ {
+ AbstractJMSMessage newMessage = new MessageConverter((MapMessage) testMapMessage).getConvertedMessage();
+ assertEquals("Converted map message String mismatch", ((JMSMapMessage) newMessage).getString("testMapString"),
+ testMapMessage.getString("testMapString"));
+ assertEquals("Converted map message Double mismatch", ((JMSMapMessage) newMessage).getDouble("testMapDouble"),
+ testMapMessage.getDouble("testMapDouble"));
+
+ }
+
+ public void testMessageConversion() throws Exception
+ {
+ Message newMessage = new NonQpidMessage();
+ setMessageProperties(newMessage);
+ mesagePropertiesTest(testTextMessage, newMessage);
+ }
+
+ private void setMessageProperties(Message message) throws JMSException
+ {
+ message.setJMSCorrelationID(JMS_CORR_ID);
+ message.setJMSDeliveryMode(JMS_DELIV_MODE);
+ message.setJMSType(JMS_TYPE);
+ message.setJMSReplyTo(JMS_REPLY_TO);
+
+ //Add non-JMS properties
+ message.setStringProperty("testProp1", "testValue1");
+ message.setDoubleProperty("testProp2", Double.MIN_VALUE);
+ }
+
+
+ private void mesagePropertiesTest(Message expectedMessage, Message actualMessage)
+ {
+ try
+ {
+ //check JMS prop values on newMessage match
+ assertEquals("JMS Correlation ID mismatch", expectedMessage.getJMSCorrelationID(), actualMessage.getJMSCorrelationID());
+ assertEquals("JMS Delivery mode mismatch", expectedMessage.getJMSDeliveryMode(), actualMessage.getJMSDeliveryMode());
+ assertEquals("JMS Type mismatch", expectedMessage.getJMSType(), actualMessage.getJMSType());
+ assertEquals("JMS Reply To mismatch", expectedMessage.getJMSReplyTo(), actualMessage.getJMSReplyTo());
+
+ //check non-JMS standard props ok too
+ assertEquals("Test String prop value mismatch", expectedMessage.getStringProperty("testProp1"),
+ actualMessage.getStringProperty("testProp1"));
+
+ assertEquals("Test Double prop value mismatch", expectedMessage.getDoubleProperty("testProp2"),
+ actualMessage.getDoubleProperty("testProp2"));
+ }
+ catch (JMSException e)
+ {
+ fail("An error occured testing the property values" + e.getCause());
+ e.printStackTrace();
+ }
+ }
+
+ protected void tearDown() throws Exception
+ {
+ super.tearDown();
+ testTextMessage = null;
+ }
+
+
+}
diff --git a/Final/java/client/src/test/java/org/apache/qpid/test/unit/message/NonQpidMessage.java b/Final/java/client/src/test/java/org/apache/qpid/test/unit/message/NonQpidMessage.java
new file mode 100644
index 0000000000..df53c796b2
--- /dev/null
+++ b/Final/java/client/src/test/java/org/apache/qpid/test/unit/message/NonQpidMessage.java
@@ -0,0 +1,411 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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 java.util.Enumeration;
+import java.util.Hashtable;
+
+import javax.jms.Destination;
+import javax.jms.JMSException;
+import javax.jms.Message;
+
+public class NonQpidMessage implements Message
+{
+ private String _JMSMessageID;
+ private long _JMSTimestamp;
+ private byte[] _JMSCorrelationIDAsBytes;
+ private String _JMSCorrelationID;
+ private Destination _JMSReplyTo;
+ private Destination _JMSDestination;
+ private int _JMSDeliveryMode;
+ private boolean _JMSRedelivered;
+ private String _JMSType;
+ private long _JMSExpiration;
+ private int _JMSPriority;
+ private Hashtable _properties;
+
+ public NonQpidMessage()
+ {
+ _properties = new Hashtable();
+ _JMSPriority = javax.jms.Message.DEFAULT_PRIORITY;
+ _JMSDeliveryMode = javax.jms.Message.DEFAULT_DELIVERY_MODE;
+ }
+
+ public String getJMSMessageID() throws JMSException
+ {
+ return _JMSMessageID;
+ }
+
+ public void setJMSMessageID(String string) throws JMSException
+ {
+ _JMSMessageID = string;
+ }
+
+ public long getJMSTimestamp() throws JMSException
+ {
+ return _JMSTimestamp;
+ }
+
+ public void setJMSTimestamp(long l) throws JMSException
+ {
+ _JMSTimestamp = l;
+ }
+
+ public byte[] getJMSCorrelationIDAsBytes() throws JMSException
+ {
+ return _JMSCorrelationIDAsBytes;
+ }
+
+ public void setJMSCorrelationIDAsBytes(byte[] bytes) throws JMSException
+ {
+ _JMSCorrelationIDAsBytes = bytes;
+ }
+
+ public void setJMSCorrelationID(String string) throws JMSException
+ {
+ _JMSCorrelationID = string;
+ }
+
+ public String getJMSCorrelationID() throws JMSException
+ {
+ return _JMSCorrelationID;
+ }
+
+ public Destination getJMSReplyTo() throws JMSException
+ {
+ return _JMSReplyTo;
+ }
+
+ public void setJMSReplyTo(Destination destination) throws JMSException
+ {
+ _JMSReplyTo = destination;
+ }
+
+ public Destination getJMSDestination() throws JMSException
+ {
+ return _JMSDestination;
+ }
+
+ public void setJMSDestination(Destination destination) throws JMSException
+ {
+ _JMSDestination = destination;
+ }
+
+ public int getJMSDeliveryMode() throws JMSException
+ {
+ return _JMSDeliveryMode;
+ }
+
+ public void setJMSDeliveryMode(int i) throws JMSException
+ {
+ _JMSDeliveryMode = i;
+ }
+
+ public boolean getJMSRedelivered() throws JMSException
+ {
+ return _JMSRedelivered;
+ }
+
+ public void setJMSRedelivered(boolean b) throws JMSException
+ {
+ _JMSRedelivered = b;
+ }
+
+ public String getJMSType() throws JMSException
+ {
+ return _JMSType;
+ }
+
+ public void setJMSType(String string) throws JMSException
+ {
+ _JMSType = string;
+ }
+
+ public long getJMSExpiration() throws JMSException
+ {
+ return _JMSExpiration;
+ }
+
+ public void setJMSExpiration(long l) throws JMSException
+ {
+ _JMSExpiration = l;
+ }
+
+ public int getJMSPriority() throws JMSException
+ {
+ return _JMSPriority;
+ }
+
+ public void setJMSPriority(int i) throws JMSException
+ {
+ _JMSPriority = i;
+ }
+
+ public void clearProperties() throws JMSException
+ {
+ _properties.clear();
+ }
+
+ public boolean propertyExists(String string) throws JMSException
+ {
+ return _properties.containsKey(string);
+ }
+
+ public boolean getBooleanProperty(String string) throws JMSException
+ {
+ if (propertyExists(string))
+ {
+ Object o = _properties.get(string);
+ if (o instanceof Boolean)
+ {
+ return (Boolean) o;
+ }
+ else
+ {
+ return Boolean.valueOf(null);
+ }
+ }
+ else
+ {
+ throw new JMSException("property does not exist: " + string);
+ }
+ }
+
+ public byte getByteProperty(String string) throws JMSException
+ {
+ if (propertyExists(string))
+ {
+ Object o = _properties.get(string);
+ if (o instanceof Byte)
+ {
+ return (Byte) o;
+ }
+ else
+ {
+ return Byte.valueOf(null);
+ }
+ }
+ else
+ {
+ throw new JMSException("property does not exist: " + string);
+ }
+ }
+
+ public short getShortProperty(String string) throws JMSException
+ {
+ if (propertyExists(string))
+ {
+ Object o = _properties.get(string);
+ if (o instanceof Short)
+ {
+ return (Short) o;
+ }
+ else
+ {
+ return Short.valueOf(null);
+ }
+ }
+ else
+ {
+ throw new JMSException("property does not exist: " + string);
+ }
+ }
+
+ public int getIntProperty(String string) throws JMSException
+ {
+ if (propertyExists(string))
+ {
+ Object o = _properties.get(string);
+ if (o instanceof Integer)
+ {
+ return (Integer) o;
+ }
+ else
+ {
+ return Integer.valueOf(null);
+ }
+ }
+ else
+ {
+ throw new JMSException("property does not exist: " + string);
+ }
+ }
+
+ public long getLongProperty(String string) throws JMSException
+ {
+ if (propertyExists(string))
+ {
+ Object o = _properties.get(string);
+ if (o instanceof Long)
+ {
+ return (Long) o;
+ }
+ else
+ {
+ return Long.valueOf(null);
+ }
+ }
+ else
+ {
+ throw new JMSException("property does not exist: " + string);
+ }
+ }
+
+ public float getFloatProperty(String string) throws JMSException
+ {
+ if (propertyExists(string))
+ {
+ Object o = _properties.get(string);
+ if (o instanceof Float)
+ {
+ return (Float) o;
+ }
+ else
+ {
+ return Float.valueOf(null);
+ }
+ }
+ else
+ {
+ throw new JMSException("property does not exist: " + string);
+ }
+ }
+
+ public double getDoubleProperty(String string) throws JMSException
+ {
+ if (propertyExists(string))
+ {
+ Object o = _properties.get(string);
+ if (o instanceof Double)
+ {
+ return (Double) o;
+ }
+ else
+ {
+ return Double.valueOf(null);
+ }
+ }
+ else
+ {
+ throw new JMSException("property does not exist: " + string);
+ }
+ }
+
+ public String getStringProperty(String string) throws JMSException
+ {
+ if (propertyExists(string))
+ {
+ Object o = _properties.get(string);
+ if (o instanceof String)
+ {
+ return (String) o;
+ }
+ else
+ {
+ return null;
+ }
+ }
+ else
+ {
+ throw new JMSException("property does not exist: " + string);
+ }
+ }
+
+ public Object getObjectProperty(String string) throws JMSException
+ {
+ if (propertyExists(string))
+ {
+ Object o = _properties.get(string);
+ if (o instanceof Boolean)
+ {
+ return (Boolean) o;
+ }
+ else
+ {
+ return Boolean.valueOf(null);
+ }
+ }
+ else
+ {
+ throw new JMSException("property does not exist: " + string);
+ }
+ }
+
+ public Enumeration getPropertyNames() throws JMSException
+ {
+ return _properties.keys();
+ }
+
+ public void setBooleanProperty(String string, boolean b) throws JMSException
+ {
+ _properties.put(string, b);
+ }
+
+ public void setByteProperty(String string, byte b) throws JMSException
+ {
+ _properties.put(string, b);
+ }
+
+ public void setShortProperty(String string, short i) throws JMSException
+ {
+ _properties.put(string, i);
+ }
+
+ public void setIntProperty(String string, int i) throws JMSException
+ {
+ _properties.put(string, i);
+ }
+
+ public void setLongProperty(String string, long l) throws JMSException
+ {
+ _properties.put(string, l);
+ }
+
+ public void setFloatProperty(String string, float v) throws JMSException
+ {
+ _properties.put(string, v);
+ }
+
+ public void setDoubleProperty(String string, double v) throws JMSException
+ {
+ _properties.put(string, v);
+ }
+
+ public void setStringProperty(String string, String string1) throws JMSException
+ {
+ _properties.put(string, string1);
+ }
+
+ public void setObjectProperty(String string, Object object) throws JMSException
+ {
+ _properties.put(string, object);
+ }
+
+ public void acknowledge() throws JMSException
+ {
+
+ }
+
+ public void clearBody() throws JMSException
+ {
+
+ }
+}
diff --git a/Final/java/client/src/test/java/org/apache/qpid/test/unit/message/StreamMessageTest.java b/Final/java/client/src/test/java/org/apache/qpid/test/unit/message/StreamMessageTest.java
new file mode 100644
index 0000000000..9c4f2af107
--- /dev/null
+++ b/Final/java/client/src/test/java/org/apache/qpid/test/unit/message/StreamMessageTest.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.message;
+
+import junit.framework.TestCase;
+
+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.transport.TransportConnection;
+import org.apache.qpid.exchange.ExchangeDefaults;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.framing.FieldTable;
+import org.apache.qpid.url.AMQBindingURL;
+import org.apache.qpid.url.BindingURL;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.jms.Connection;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageEOFException;
+import javax.jms.MessageListener;
+import javax.jms.MessageProducer;
+import javax.jms.Session;
+import javax.jms.StreamMessage;
+
+/**
+ * @author Apache Software Foundation
+ */
+public class StreamMessageTest extends TestCase
+{
+
+ private static final Logger _logger = LoggerFactory.getLogger(StreamMessageTest.class);
+
+ public String _connectionString = "vm://:1";
+
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+ TransportConnection.createVMBroker(1);
+ }
+
+ protected void tearDown() throws Exception
+ {
+ super.tearDown();
+ TransportConnection.killAllVMBrokers();
+ }
+
+ public void testStreamMessageEOF() throws Exception
+ {
+ Connection con = new AMQConnection("vm://:1", "guest", "guest", "consumer1", "test");
+ AMQSession consumerSession = (AMQSession) con.createSession(false, Session.CLIENT_ACKNOWLEDGE);
+
+ AMQHeadersExchange 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");
+ MessageConsumer consumer =
+ consumerSession.createConsumer(queue, AMQSession.DEFAULT_PREFETCH_LOW_MARK,
+ AMQSession.DEFAULT_PREFETCH_HIGH_MARK, 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
+
+ Connection con2 = new AMQConnection("vm://:1", "guest", "guest", "producer1", "test");
+
+ AMQSession producerSession = (AMQSession) con2.createSession(false, Session.CLIENT_ACKNOWLEDGE);
+
+ // Need to start the "producer" connection in order to receive bounced messages
+ _logger.info("Starting producer connection");
+ con2.start();
+
+ MessageProducer mandatoryProducer = producerSession.createProducer(queue);
+
+ // Third test - should be routed
+ _logger.info("Sending isBound message");
+ StreamMessage msg = producerSession.createStreamMessage();
+
+ msg.setStringProperty("F1000", "1");
+
+ msg.writeByte((byte) 42);
+
+ mandatoryProducer.send(msg);
+
+ _logger.info("Starting consumer connection");
+ con.start();
+
+ StreamMessage msg2 = (StreamMessage) consumer.receive();
+
+ msg2.readByte();
+ try
+ {
+ msg2.readByte();
+ }
+ catch (Exception e)
+ {
+ assertTrue("Expected MessageEOFException: " + e, e instanceof MessageEOFException);
+ }
+ }
+
+ public void testModifyReceivedMessageExpandsBuffer() throws Exception
+ {
+ AMQConnection con = new AMQConnection("vm://:1", "guest", "guest", "consumer1", "test");
+ AMQSession consumerSession = (AMQSession) con.createSession(false, Session.CLIENT_ACKNOWLEDGE);
+ AMQQueue queue = new AMQQueue(con.getDefaultQueueExchangeName(), new AMQShortString("testQ"));
+ MessageConsumer consumer = consumerSession.createConsumer(queue);
+ consumer.setMessageListener(new MessageListener()
+ {
+
+ public void onMessage(Message message)
+ {
+ StreamMessage sm = (StreamMessage) message;
+ try
+ {
+ sm.clearBody();
+ sm.writeString("dfgjshfslfjshflsjfdlsjfhdsljkfhdsljkfhsd");
+ }
+ catch (JMSException e)
+ {
+ _logger.error("Error when writing large string to received msg: " + e, e);
+ fail("Error when writing large string to received msg" + e);
+ }
+ }
+ });
+
+ Connection con2 = new AMQConnection("vm://:1", "guest", "guest", "producer1", "test");
+ AMQSession producerSession = (AMQSession) con2.createSession(false, Session.CLIENT_ACKNOWLEDGE);
+ MessageProducer mandatoryProducer = producerSession.createProducer(queue);
+ con.start();
+ StreamMessage sm = producerSession.createStreamMessage();
+ sm.writeInt(42);
+ mandatoryProducer.send(sm);
+ Thread.sleep(2000);
+ }
+}
diff --git a/Final/java/client/src/test/java/org/apache/qpid/test/unit/topic/DurableSubscriptionTest.java b/Final/java/client/src/test/java/org/apache/qpid/test/unit/topic/DurableSubscriptionTest.java
new file mode 100644
index 0000000000..a0a8eb10ed
--- /dev/null
+++ b/Final/java/client/src/test/java/org/apache/qpid/test/unit/topic/DurableSubscriptionTest.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.test.unit.topic;
+
+import junit.framework.TestCase;
+
+import org.apache.qpid.AMQException;
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.client.AMQSession;
+import org.apache.qpid.client.AMQTopic;
+import org.apache.qpid.client.transport.TransportConnection;
+import org.apache.qpid.url.URLSyntaxException;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+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 javax.jms.TopicSubscriber;
+
+public class DurableSubscriptionTest extends TestCase
+{
+ private static final Logger _logger = LoggerFactory.getLogger(DurableSubscriptionTest.class);
+
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+ TransportConnection.createVMBroker(1);
+ }
+
+ protected void tearDown() throws Exception
+ {
+ super.tearDown();
+ TransportConnection.killAllVMBrokers();
+ }
+
+ public void testUnsubscribe() throws AMQException, JMSException, URLSyntaxException
+ {
+ AMQConnection con = new AMQConnection("vm://:1", "guest", "guest", "test", "test");
+ AMQTopic topic = new AMQTopic(con, "MyTopic");
+ _logger.info("Create Session 1");
+ Session session1 = con.createSession(false, AMQSession.NO_ACKNOWLEDGE);
+ _logger.info("Create Consumer on Session 1");
+ MessageConsumer consumer1 = session1.createConsumer(topic);
+ _logger.info("Create Producer on Session 1");
+ MessageProducer producer = session1.createProducer(topic);
+
+ _logger.info("Create Session 2");
+ Session session2 = con.createSession(false, AMQSession.NO_ACKNOWLEDGE);
+ _logger.info("Create Durable Subscriber on Session 2");
+ TopicSubscriber consumer2 = session2.createDurableSubscriber(topic, "MySubscription");
+
+ _logger.info("Starting connection");
+ con.start();
+
+ _logger.info("Producer sending message A");
+ producer.send(session1.createTextMessage("A"));
+
+ Message msg;
+ _logger.info("Receive message on consumer 1:expecting A");
+ msg = consumer1.receive();
+ assertEquals("A", ((TextMessage) msg).getText());
+ _logger.info("Receive message on consumer 1 :expecting null");
+ msg = consumer1.receive(1000);
+ assertEquals(null, msg);
+
+ _logger.info("Receive message on consumer 1:expecting A");
+ msg = consumer2.receive();
+ assertEquals("A", ((TextMessage) msg).getText());
+ msg = consumer2.receive(1000);
+ _logger.info("Receive message on consumer 1 :expecting null");
+ assertEquals(null, msg);
+
+ _logger.info("Unsubscribe session2/consumer2");
+ session2.unsubscribe("MySubscription");
+
+ _logger.info("Producer sending message B");
+ producer.send(session1.createTextMessage("B"));
+
+ _logger.info("Receive message on consumer 1 :expecting B");
+ msg = consumer1.receive();
+ assertEquals("B", ((TextMessage) msg).getText());
+ _logger.info("Receive message on consumer 1 :expecting null");
+ msg = consumer1.receive(1000);
+ assertEquals(null, msg);
+
+ _logger.info("Receive message on consumer 2 :expecting null");
+ msg = consumer2.receive(1000);
+ assertEquals(null, msg);
+
+ _logger.info("Close connection");
+ con.close();
+ }
+
+ public void testDurabilityNOACK() throws AMQException, JMSException, URLSyntaxException
+ {
+ durabilityImpl(AMQSession.NO_ACKNOWLEDGE);
+ }
+
+ public void testDurabilityAUTOACK() throws AMQException, JMSException, URLSyntaxException
+ {
+ durabilityImpl(Session.AUTO_ACKNOWLEDGE);
+ }
+
+ private void durabilityImpl(int ackMode) throws AMQException, JMSException, URLSyntaxException
+ {
+
+ AMQConnection con = new AMQConnection("vm://:1", "guest", "guest", "test", "test");
+ AMQTopic topic = new AMQTopic(con, "MyTopic");
+ Session session1 = con.createSession(false, ackMode);
+ MessageConsumer consumer1 = session1.createConsumer(topic);
+
+ Session sessionProd = con.createSession(false, ackMode);
+ MessageProducer producer = sessionProd.createProducer(topic);
+
+ Session session2 = con.createSession(false, ackMode);
+ TopicSubscriber consumer2 = session2.createDurableSubscriber(topic, "MySubscription");
+
+ con.start();
+
+ producer.send(session1.createTextMessage("A"));
+
+ Message msg;
+ msg = consumer1.receive(500);
+ assertNotNull("Message should be available", msg);
+ assertEquals("Message Text doesn't match", "A", ((TextMessage) msg).getText());
+
+ msg = consumer1.receive(500);
+ assertNull("There should be no more messages for consumption on consumer1.", msg);
+
+ msg = consumer2.receive();
+ assertNotNull(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);
+
+ consumer2.close();
+
+ Session session3 = con.createSession(false, ackMode);
+ MessageConsumer consumer3 = session3.createDurableSubscriber(topic, "MySubscription");
+
+ producer.send(session1.createTextMessage("B"));
+
+ _logger.info("Receive message on consumer 1 :expecting B");
+ msg = consumer1.receive(500);
+ assertNotNull("Consumer 1 should get message 'B'.", msg);
+ assertEquals("Incorrect Message recevied on consumer1.", "B", ((TextMessage) msg).getText());
+ _logger.info("Receive message on consumer 1 :expecting null");
+ msg = consumer1.receive(500);
+ assertNull("There should be no more messages for consumption on consumer1.", msg);
+
+ _logger.info("Receive message on consumer 3 :expecting B");
+ msg = consumer3.receive(500);
+ assertNotNull("Consumer 3 should get message 'B'.", msg);
+ assertEquals("Incorrect Message recevied on consumer4.", "B", ((TextMessage) msg).getText());
+ _logger.info("Receive message on consumer 3 :expecting null");
+ msg = consumer3.receive(500);
+ assertNull("There should be no more messages for consumption on consumer3.", msg);
+
+ consumer1.close();
+ consumer3.close();
+
+ con.close();
+ }
+
+ public static junit.framework.Test suite()
+ {
+ return new junit.framework.TestSuite(DurableSubscriptionTest.class);
+ }
+}
diff --git a/Final/java/client/src/test/java/org/apache/qpid/test/unit/topic/TopicPublisherTest.java b/Final/java/client/src/test/java/org/apache/qpid/test/unit/topic/TopicPublisherTest.java
new file mode 100644
index 0000000000..929e2799a9
--- /dev/null
+++ b/Final/java/client/src/test/java/org/apache/qpid/test/unit/topic/TopicPublisherTest.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.test.unit.topic;
+
+import javax.jms.MessageConsumer;
+import javax.jms.TextMessage;
+import javax.jms.TopicPublisher;
+import javax.jms.TopicSession;
+
+import junit.framework.TestCase;
+
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.client.AMQSession;
+import org.apache.qpid.client.AMQTopic;
+import org.apache.qpid.client.transport.TransportConnection;
+
+/**
+ * @author Apache Software Foundation
+ */
+public class TopicPublisherTest extends TestCase
+{
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+ TransportConnection.createVMBroker(1);
+ }
+
+ protected void tearDown() throws Exception
+ {
+ super.tearDown();
+ TransportConnection.killAllVMBrokers();
+ }
+
+ public void testUnidentifiedProducer() throws Exception
+ {
+
+ AMQConnection con = new AMQConnection("vm://:1", "guest", "guest", "test", "test");
+ AMQTopic topic = new AMQTopic(con,"MyTopic");
+ TopicSession session1 = con.createTopicSession(false, AMQSession.NO_ACKNOWLEDGE);
+ TopicPublisher publisher = session1.createPublisher(null);
+ MessageConsumer consumer1 = session1.createConsumer(topic);
+ con.start();
+ publisher.publish(topic, session1.createTextMessage("Hello"));
+ TextMessage m = (TextMessage) consumer1.receive(2000);
+ assertNotNull(m);
+ try
+ {
+ publisher.publish(session1.createTextMessage("Goodbye"));
+ fail("Did not throw UnsupportedOperationException");
+ }
+ catch (UnsupportedOperationException e)
+ {
+ // PASS
+ }
+
+ }
+
+ public static junit.framework.Test suite()
+ {
+ return new junit.framework.TestSuite(TopicPublisherTest.class);
+ }
+}
diff --git a/Final/java/client/src/test/java/org/apache/qpid/test/unit/topic/TopicSessionTest.java b/Final/java/client/src/test/java/org/apache/qpid/test/unit/topic/TopicSessionTest.java
new file mode 100644
index 0000000000..065b06a87d
--- /dev/null
+++ b/Final/java/client/src/test/java/org/apache/qpid/test/unit/topic/TopicSessionTest.java
@@ -0,0 +1,375 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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.topic;
+
+import javax.jms.InvalidDestinationException;
+import javax.jms.JMSException;
+import javax.jms.MessageConsumer;
+import javax.jms.Session;
+import javax.jms.TemporaryTopic;
+import javax.jms.TextMessage;
+import javax.jms.TopicPublisher;
+import javax.jms.TopicSession;
+import javax.jms.TopicSubscriber;
+
+import junit.framework.TestCase;
+
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.client.AMQSession;
+import org.apache.qpid.client.AMQTopic;
+import org.apache.qpid.client.transport.TransportConnection;
+
+
+/** @author Apache Software Foundation */
+public class TopicSessionTest extends TestCase
+{
+ private static final String BROKER = "vm://:1";
+
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+ TransportConnection.createVMBroker(1);
+ }
+
+ protected void tearDown() throws Exception
+ {
+ super.tearDown();
+ TransportConnection.killAllVMBrokers();
+ }
+
+
+ public void testTopicSubscriptionUnsubscription() throws Exception
+ {
+
+ AMQConnection con = new AMQConnection(BROKER+"?retries='0'", "guest", "guest", "test", "test");
+ AMQTopic topic = new AMQTopic(con.getDefaultTopicExchangeName(), "MyTopic");
+ TopicSession session1 = con.createTopicSession(false, AMQSession.NO_ACKNOWLEDGE);
+ TopicSubscriber sub = session1.createDurableSubscriber(topic, "subscription0");
+ TopicPublisher publisher = session1.createPublisher(topic);
+
+ con.start();
+
+ TextMessage tm = session1.createTextMessage("Hello");
+ publisher.publish(tm);
+
+ tm = (TextMessage) sub.receive(2000);
+ assertNotNull(tm);
+
+ session1.unsubscribe("subscription0");
+
+ try
+ {
+ session1.unsubscribe("not a subscription");
+ fail("expected InvalidDestinationException when unsubscribing from unknown subscription");
+ }
+ catch (InvalidDestinationException e)
+ {
+ ; // PASS
+ }
+ catch (Exception e)
+ {
+ fail("expected InvalidDestinationException when unsubscribing from unknown subscription, got: " + e);
+ }
+
+ con.close();
+ }
+
+ public void testSubscriptionNameReuseForDifferentTopicSingleConnection() throws Exception
+ {
+ subscriptionNameReuseForDifferentTopic(false);
+ }
+
+ public void testSubscriptionNameReuseForDifferentTopicTwoConnections() throws Exception
+ {
+ subscriptionNameReuseForDifferentTopic(true);
+ }
+
+ private void subscriptionNameReuseForDifferentTopic(boolean shutdown) throws Exception
+ {
+ AMQConnection con = new AMQConnection("vm://:1?retries='0'", "guest", "guest", "test", "test");
+ AMQTopic topic = new AMQTopic(con, "MyTopic1" + String.valueOf(shutdown));
+ AMQTopic topic2 = new AMQTopic(con, "MyOtherTopic1" + String.valueOf(shutdown));
+
+ TopicSession session1 = con.createTopicSession(false, AMQSession.NO_ACKNOWLEDGE);
+ TopicSubscriber sub = session1.createDurableSubscriber(topic, "subscription0");
+ TopicPublisher publisher = session1.createPublisher(null);
+
+ con.start();
+
+ publisher.publish(topic, session1.createTextMessage("hello"));
+ TextMessage m = (TextMessage) sub.receive(2000);
+ assertNotNull(m);
+
+ if (shutdown)
+ {
+ session1.close();
+ con.close();
+ con = new AMQConnection("vm://:1?retries='0'", "guest", "guest", "test", "test");
+ con.start();
+ session1 = con.createTopicSession(false, AMQSession.NO_ACKNOWLEDGE);
+ publisher = session1.createPublisher(null);
+ }
+ TopicSubscriber sub2 = session1.createDurableSubscriber(topic2, "subscription0");
+ publisher.publish(topic, session1.createTextMessage("hello"));
+ if (!shutdown)
+ {
+ m = (TextMessage) sub.receive(2000);
+ assertNull(m);
+ }
+ publisher.publish(topic2, session1.createTextMessage("goodbye"));
+ m = (TextMessage) sub2.receive(2000);
+ assertNotNull(m);
+ assertEquals("goodbye", m.getText());
+ con.close();
+ }
+
+ public void testUnsubscriptionAfterConnectionClose() throws Exception
+ {
+ AMQConnection con1 = new AMQConnection("vm://:1?retries='0'", "guest", "guest", "test", "test");
+ AMQTopic topic = new AMQTopic(con1, "MyTopic3");
+
+ TopicSession session1 = con1.createTopicSession(false, AMQSession.NO_ACKNOWLEDGE);
+ TopicPublisher publisher = session1.createPublisher(topic);
+
+ AMQConnection con2 = new AMQConnection("vm://:1?retries='0'", "guest", "guest", "test2", "test");
+ TopicSession session2 = con2.createTopicSession(false, AMQSession.NO_ACKNOWLEDGE);
+ TopicSubscriber sub = session2.createDurableSubscriber(topic, "subscription0");
+
+ con2.start();
+
+ publisher.publish(session1.createTextMessage("Hello"));
+ TextMessage tm = (TextMessage) sub.receive(2000);
+ assertNotNull(tm);
+ con2.close();
+ publisher.publish(session1.createTextMessage("Hello2"));
+ con2 = new AMQConnection("vm://:1?retries='0'", "guest", "guest", "test2", "test");
+ session2 = con2.createTopicSession(false, AMQSession.NO_ACKNOWLEDGE);
+ sub = session2.createDurableSubscriber(topic, "subscription0");
+ con2.start();
+ tm = (TextMessage) sub.receive(2000);
+ assertNotNull(tm);
+ assertEquals("Hello2", tm.getText());
+ con1.close();
+ con2.close();
+ }
+
+ public void testTextMessageCreation() throws Exception
+ {
+
+ AMQConnection con = new AMQConnection("vm://:1?retries='0'", "guest", "guest", "test", "test");
+ AMQTopic topic = new AMQTopic(con, "MyTopic4");
+ TopicSession session1 = con.createTopicSession(false, AMQSession.NO_ACKNOWLEDGE);
+ TopicPublisher publisher = session1.createPublisher(topic);
+ MessageConsumer consumer1 = session1.createConsumer(topic);
+ con.start();
+ TextMessage tm = session1.createTextMessage("Hello");
+ publisher.publish(tm);
+ tm = (TextMessage) consumer1.receive(200000L);
+ assertNotNull(tm);
+ String msgText = tm.getText();
+ assertEquals("Hello", msgText);
+ tm = session1.createTextMessage();
+ msgText = tm.getText();
+ assertNull(msgText);
+ publisher.publish(tm);
+ tm = (TextMessage) consumer1.receive(20000000L);
+ assertNotNull(tm);
+ msgText = tm.getText();
+ assertNull(msgText);
+ tm.clearBody();
+ tm.setText("Now we are not null");
+ publisher.publish(tm);
+ tm = (TextMessage) consumer1.receive(2000);
+ assertNotNull(tm);
+ msgText = tm.getText();
+ assertEquals("Now we are not null", msgText);
+
+ tm = session1.createTextMessage("");
+ msgText = tm.getText();
+ assertEquals("Empty string not returned", "", msgText);
+ publisher.publish(tm);
+ tm = (TextMessage) consumer1.receive(2000);
+ assertNotNull(tm);
+ assertEquals("Empty string not returned", "", msgText);
+ con.close();
+ }
+
+ public void testSendingSameMessage() throws Exception
+ {
+ AMQConnection conn = new AMQConnection("vm://:1?retries='0'", "guest", "guest", "test", "test");
+ TopicSession session = conn.createTopicSession(false, Session.AUTO_ACKNOWLEDGE);
+ TemporaryTopic topic = session.createTemporaryTopic();
+ assertNotNull(topic);
+ TopicPublisher producer = session.createPublisher(topic);
+ MessageConsumer consumer = session.createConsumer(topic);
+ conn.start();
+ TextMessage sentMessage = session.createTextMessage("Test Message");
+ producer.send(sentMessage);
+ TextMessage receivedMessage = (TextMessage) consumer.receive(2000);
+ assertNotNull(receivedMessage);
+ assertEquals(sentMessage.getText(), receivedMessage.getText());
+ producer.send(sentMessage);
+ receivedMessage = (TextMessage) consumer.receive(2000);
+ assertNotNull(receivedMessage);
+ assertEquals(sentMessage.getText(), receivedMessage.getText());
+
+ conn.close();
+
+ }
+
+ public void testTemporaryTopic() throws Exception
+ {
+ AMQConnection conn = new AMQConnection("vm://:1?retries='0'", "guest", "guest", "test", "test");
+ TopicSession session = conn.createTopicSession(false, 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"));
+ TextMessage tm = (TextMessage) consumer.receive(2000);
+ assertNotNull(tm);
+ assertEquals("hello", tm.getText());
+
+ try
+ {
+ topic.delete();
+ fail("Expected JMSException : should not be able to delete while there are active consumers");
+ }
+ catch (JMSException je)
+ {
+ ; //pass
+ }
+
+ consumer.close();
+
+ try
+ {
+ topic.delete();
+ }
+ catch (JMSException je)
+ {
+ fail("Unexpected Exception: " + je.getMessage());
+ }
+
+ TopicSession session2 = conn.createTopicSession(false, Session.AUTO_ACKNOWLEDGE);
+ try
+ {
+ session2.createConsumer(topic);
+ fail("Expected a JMSException when subscribing to a temporary topic created on adifferent session");
+ }
+ catch (JMSException je)
+ {
+ ; // pass
+ }
+
+
+ conn.close();
+ }
+
+
+ public void testNoLocal() throws Exception
+ {
+
+ AMQConnection con = new AMQConnection(BROKER + "?retries='0'", "guest", "guest", "test", "test");
+
+ AMQTopic topic = new AMQTopic(con, "testNoLocal");
+
+ TopicSession session1 = con.createTopicSession(false, AMQSession.NO_ACKNOWLEDGE);
+ TopicSubscriber noLocal = session1.createDurableSubscriber(topic, "noLocal", "", true);
+ TopicSubscriber select = session1.createDurableSubscriber(topic, "select", "Selector = 'select'", false);
+ TopicSubscriber normal = session1.createDurableSubscriber(topic, "normal");
+
+ TopicPublisher publisher = session1.createPublisher(topic);
+
+ con.start();
+ TextMessage m;
+ TextMessage message;
+
+ //send message to all consumers
+ publisher.publish(session1.createTextMessage("hello-new2"));
+
+ //test normal subscriber gets message
+ m = (TextMessage) normal.receive(5000);
+ assertNotNull(m);
+
+ //test selector subscriber doesn't message
+ m = (TextMessage) select.receive(2000);
+ assertNull(m);
+
+ //test nolocal subscriber doesn't message
+ m = (TextMessage) noLocal.receive(2000);
+ if (m != null)
+ {
+ System.out.println("Message:" + m.getText());
+ }
+ assertNull(m);
+
+ //send message to all consumers
+ message = session1.createTextMessage("hello2");
+ message.setStringProperty("Selector", "select");
+
+ publisher.publish(message);
+
+ //test normal subscriber gets message
+ m = (TextMessage) normal.receive(5000);
+ assertNotNull(m);
+
+ //test selector subscriber does get message
+ m = (TextMessage) select.receive(2000);
+ assertNotNull(m);
+
+ //test nolocal subscriber doesn't message
+ m = (TextMessage) noLocal.receive(1000);
+ assertNull(m);
+
+ AMQConnection con2 = new AMQConnection(BROKER + "?retries='0'", "guest", "guest", "test2", "test");
+ TopicSession session2 = con2.createTopicSession(false, AMQSession.NO_ACKNOWLEDGE);
+ TopicPublisher publisher2 = session2.createPublisher(topic);
+
+
+ message = session2.createTextMessage("hello2");
+ message.setStringProperty("Selector", "select");
+
+ publisher2.publish(message);
+
+ //test normal subscriber gets message
+ m = (TextMessage) normal.receive(2000);
+ assertNotNull(m);
+
+ //test selector subscriber does get message
+ m = (TextMessage) select.receive(2000);
+ assertNotNull(m);
+
+ //test nolocal subscriber does message
+ m = (TextMessage) noLocal.receive(2000);
+ assertNotNull(m);
+
+
+ con.close();
+ con2.close();
+ }
+
+ public static junit.framework.Test suite()
+ {
+ return new junit.framework.TestSuite(TopicSessionTest.class);
+ }
+}
diff --git a/Final/java/client/src/test/java/org/apache/qpid/test/unit/transacted/CommitRollbackTest.java b/Final/java/client/src/test/java/org/apache/qpid/test/unit/transacted/CommitRollbackTest.java
new file mode 100644
index 0000000000..224463a446
--- /dev/null
+++ b/Final/java/client/src/test/java/org/apache/qpid/test/unit/transacted/CommitRollbackTest.java
@@ -0,0 +1,532 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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.transacted;
+
+import junit.framework.TestCase;
+import org.apache.qpid.AMQException;
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.client.transport.TransportConnection;
+import org.apache.qpid.url.URLSyntaxException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+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;
+
+/**
+ * This class tests a number of commits and roll back scenarios
+ *
+ * Assumptions; - Assumes empty Queue
+ */
+public class CommitRollbackTest extends TestCase
+{
+ protected AMQConnection conn;
+ protected String queue = "direct://amq.direct//Qpid.Client.Transacted.CommitRollback.queue";
+ protected static int testMethod = 0;
+ protected String payload = "xyzzy";
+ private Session _session;
+ private MessageProducer _publisher;
+ private Session _pubSession;
+ private MessageConsumer _consumer;
+ Queue _jmsQueue;
+
+ private static final Logger _logger = LoggerFactory.getLogger(CommitRollbackTest.class);
+ private static final String BROKER = "vm://:1";
+ private boolean _gotone = false;
+ private boolean _gottwo = false;
+ private boolean _gottwoRedelivered = false;
+
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+ if (BROKER.startsWith("vm"))
+ {
+ TransportConnection.createVMBroker(1);
+ }
+
+ testMethod++;
+ queue += testMethod;
+
+ newConnection();
+ }
+
+ private void newConnection() throws AMQException, URLSyntaxException, JMSException
+ {
+ conn = new AMQConnection("amqp://guest:guest@client/test?brokerlist='" + BROKER + "'");
+
+ _session = conn.createSession(true, Session.CLIENT_ACKNOWLEDGE);
+
+ _jmsQueue = _session.createQueue(queue);
+ _consumer = _session.createConsumer(_jmsQueue);
+
+ _pubSession = conn.createSession(true, Session.CLIENT_ACKNOWLEDGE);
+
+ _publisher = _pubSession.createProducer(_pubSession.createQueue(queue));
+
+ conn.start();
+ }
+
+ protected void tearDown() throws Exception
+ {
+ super.tearDown();
+
+ conn.close();
+ if (BROKER.startsWith("vm"))
+ {
+ TransportConnection.killVMBroker(1);
+ }
+ }
+
+ /**
+ * PUT a text message, disconnect before commit, confirm it is gone.
+ *
+ * @throws Exception On error
+ */
+ public void testPutThenDisconnect() throws Exception
+ {
+ assertTrue("session is not transacted", _session.getTransacted());
+ assertTrue("session is not transacted", _pubSession.getTransacted());
+
+ _logger.info("sending test message");
+ String MESSAGE_TEXT = "testPutThenDisconnect";
+ _publisher.send(_pubSession.createTextMessage(MESSAGE_TEXT));
+
+ _logger.info("reconnecting without commit");
+ conn.close();
+
+ newConnection();
+
+ _logger.info("receiving result");
+ Message result = _consumer.receive(1000);
+
+ // commit to ensure message is removed from queue
+ _session.commit();
+
+ assertNull("test message was put and disconnected before commit, but is still present", result);
+ }
+
+ /**
+ * PUT a text message, disconnect before commit, confirm it is gone.
+ *
+ * @throws Exception On error
+ */
+ public void testPutThenCloseDisconnect() throws Exception
+ {
+ assertTrue("session is not transacted", _session.getTransacted());
+ assertTrue("session is not transacted", _pubSession.getTransacted());
+
+ _logger.info("sending test message");
+ String MESSAGE_TEXT = "testPutThenDisconnect";
+ _publisher.send(_pubSession.createTextMessage(MESSAGE_TEXT));
+
+ _logger.info("closing publisher without commit");
+ _publisher.close();
+
+ _logger.info("reconnecting without commit");
+ conn.close();
+
+ newConnection();
+
+ _logger.info("receiving result");
+ Message result = _consumer.receive(1000);
+
+ // commit to ensure message is removed from queue
+ _session.commit();
+
+ assertNull("test message was put and disconnected before commit, but is still present", result);
+ }
+
+ /**
+ * PUT a text message, rollback, confirm message is gone. The consumer is on the same connection but different
+ * session as producer
+ *
+ * @throws Exception On error
+ */
+ public void testPutThenRollback() throws Exception
+ {
+ assertTrue("session is not transacted", _session.getTransacted());
+ assertTrue("session is not transacted", _pubSession.getTransacted());
+
+ _logger.info("sending test message");
+ String MESSAGE_TEXT = "testPutThenRollback";
+ _publisher.send(_pubSession.createTextMessage(MESSAGE_TEXT));
+
+ _logger.info("rolling back");
+ _pubSession.rollback();
+
+ _logger.info("receiving result");
+ Message result = _consumer.receive(1000);
+
+ assertNull("test message was put and rolled back, but is still present", result);
+ }
+
+ /**
+ * GET a text message, disconnect before commit, confirm it is still there. The consumer is on a new connection
+ *
+ * @throws Exception On error
+ */
+ public void testGetThenDisconnect() throws Exception
+ {
+ assertTrue("session is not transacted", _session.getTransacted());
+ assertTrue("session is not transacted", _pubSession.getTransacted());
+
+ _logger.info("sending test message");
+ String MESSAGE_TEXT = "testGetThenDisconnect";
+ _publisher.send(_pubSession.createTextMessage(MESSAGE_TEXT));
+
+ _pubSession.commit();
+
+ _logger.info("getting test message");
+
+ Message msg = _consumer.receive(5000);
+ assertNotNull("retrieved message is null", msg);
+
+ _logger.info("closing connection");
+ conn.close();
+
+ newConnection();
+
+ _logger.info("receiving result");
+ Message result = _consumer.receive(5000);
+
+ _session.commit();
+
+ assertNotNull("test message was consumed and disconnected before commit, but is gone", result);
+ assertEquals("test message was correct message", MESSAGE_TEXT, ((TextMessage) result).getText());
+ }
+
+ /**
+ * GET a text message, close consumer, disconnect before commit, confirm it is still there. The consumer is on the
+ * same connection but different session as producer
+ *
+ * @throws Exception On error
+ */
+ public void testGetThenCloseDisconnect() throws Exception
+ {
+ assertTrue("session is not transacted", _session.getTransacted());
+ assertTrue("session is not transacted", _pubSession.getTransacted());
+
+ _logger.info("sending test message");
+ String MESSAGE_TEXT = "testGetThenCloseDisconnect";
+ _publisher.send(_pubSession.createTextMessage(MESSAGE_TEXT));
+
+ _pubSession.commit();
+
+ _logger.info("getting test message");
+
+ Message msg = _consumer.receive(5000);
+ assertNotNull("retrieved message is null", msg);
+ assertEquals("test message was correct message", MESSAGE_TEXT, ((TextMessage) msg).getText());
+
+ _logger.info("reconnecting without commit");
+ _consumer.close();
+ conn.close();
+
+ newConnection();
+
+ _logger.info("receiving result");
+ Message result = _consumer.receive(5000);
+
+ _session.commit();
+
+ assertNotNull("test message was consumed and disconnected before commit, but is gone", result);
+ assertEquals("test message was correct message", MESSAGE_TEXT, ((TextMessage) result).getText());
+ }
+
+ /**
+ * GET a text message, rollback, confirm it is still there. The consumer is on the same connection but differnt
+ * session to the producer
+ *
+ * @throws Exception On error
+ */
+ public void testGetThenRollback() throws Exception
+ {
+ assertTrue("session is not transacted", _session.getTransacted());
+ assertTrue("session is not transacted", _pubSession.getTransacted());
+
+ _logger.info("sending test message");
+ String MESSAGE_TEXT = "testGetThenRollback";
+ _publisher.send(_pubSession.createTextMessage(MESSAGE_TEXT));
+
+ _pubSession.commit();
+
+ _logger.info("getting test message");
+
+ Message msg = _consumer.receive(1000);
+
+ assertNotNull("retrieved message is null", msg);
+ assertEquals("test message was correct message", MESSAGE_TEXT, ((TextMessage) msg).getText());
+
+ _logger.info("rolling back");
+
+ _session.rollback();
+
+ _logger.info("receiving result");
+
+ Message result = _consumer.receive(1000);
+
+ _session.commit();
+ assertNotNull("test message was consumed and rolled back, but is gone", result);
+ assertEquals("test message was correct message", MESSAGE_TEXT, ((TextMessage) result).getText());
+ assertTrue("Messasge is not marked as redelivered", result.getJMSRedelivered());
+ }
+
+ /**
+ * GET a text message, close message producer, rollback, confirm it is still there. The consumer is on the same
+ * connection but different session as producer
+ *
+ * @throws Exception On error
+ */
+ public void testGetThenCloseRollback() throws Exception
+ {
+ assertTrue("session is not transacted", _session.getTransacted());
+ assertTrue("session is not transacted", _pubSession.getTransacted());
+
+ _logger.info("sending test message");
+ String MESSAGE_TEXT = "testGetThenCloseRollback";
+ _publisher.send(_pubSession.createTextMessage(MESSAGE_TEXT));
+
+ _pubSession.commit();
+
+ _logger.info("getting test message");
+
+ Message msg = _consumer.receive(5000);
+
+ assertNotNull("retrieved message is null", msg);
+ assertEquals("test message was correct message", MESSAGE_TEXT, ((TextMessage) msg).getText());
+
+ _logger.info("Closing consumer");
+ _consumer.close();
+
+ _logger.info("rolling back");
+ _session.rollback();
+
+ _logger.info("receiving result");
+
+ _consumer = _session.createConsumer(_jmsQueue);
+
+ Message result = _consumer.receive(5000);
+
+ _session.commit();
+ assertNotNull("test message was consumed and rolled back, but is gone", result);
+ assertEquals("test message was correct message", MESSAGE_TEXT, ((TextMessage) result).getText());
+ assertTrue("Messasge is not marked as redelivered", result.getJMSRedelivered());
+ }
+
+ /**
+ * Test that rolling back a session purges the dispatcher queue, and the messages arrive in the correct order
+ *
+ * @throws Exception On error
+ */
+ public void testSend2ThenRollback() throws Exception
+ {
+ int run = 0;
+ while (run < 10)
+ {
+ run++;
+ _logger.info("Run:" + run);
+ assertTrue("session is not transacted", _session.getTransacted());
+ assertTrue("session is not transacted", _pubSession.getTransacted());
+
+ _logger.info("sending two test messages");
+ _publisher.send(_pubSession.createTextMessage("1"));
+ _publisher.send(_pubSession.createTextMessage("2"));
+ _pubSession.commit();
+
+ _logger.info("getting test message");
+ assertEquals("1", ((TextMessage) _consumer.receive(1000)).getText());
+
+ _logger.info("rolling back");
+ _session.rollback();
+
+ _logger.info("receiving result");
+ Message result = _consumer.receive(5000);
+
+ assertNotNull("test message was consumed and rolled back, but is gone", result);
+
+ // Message Order is:
+
+ // Send 1 , 2
+ // Retrieve 1 and then rollback
+ // Receieve 1 (redelivered) , 2 (may or may not be redelivered??)
+
+ verifyMessages(result);
+
+ // Occassionally get message 2 first!
+// assertEquals("Should get message one first", "1", ((TextMessage) result).getText());
+// assertTrue("Message is not marked as redelivered", result.getJMSRedelivered());
+//
+// result = _consumer.receive(1000);
+// assertEquals("Second message should be message 2", "2", ((TextMessage) result).getText());
+// assertTrue("Message is not marked as redelivered", result.getJMSRedelivered());
+//
+// result = _consumer.receive(1000);
+// assertNull("There should be no more messages", result);
+
+ _session.commit();
+ }
+ }
+
+ private void verifyMessages(Message result) throws JMSException
+ {
+
+ if (result == null)
+ {
+ assertTrue("Didn't receive redelivered message one", _gotone);
+ assertTrue("Didn't receive message two at all", _gottwo | _gottwoRedelivered);
+ _gotone = false;
+ _gottwo = false;
+ _gottwoRedelivered = false;
+ return;
+ }
+
+ if (((TextMessage) result).getText().equals("1"))
+ {
+ _logger.info("Got 1 redelivered");
+ assertTrue("Message is not marked as redelivered", result.getJMSRedelivered());
+ _gotone = true;
+
+ }
+ else
+ {
+ assertEquals("2", ((TextMessage) result).getText());
+
+ if (result.getJMSRedelivered())
+ {
+ _logger.info("Got 2 redelivered, message was prefetched");
+ _gottwoRedelivered = true;
+
+ }
+ else
+ {
+ _logger.warn("Got 2, message prefetched wasn't cleared or messages was in transit when rollback occured");
+ assertFalse("Already received message two", _gottwo);
+ assertFalse("Already received message redelivered two", _gottwoRedelivered);
+
+ _gottwo = true;
+ }
+ }
+
+ verifyMessages(_consumer.receive(1000));
+ }
+
+ /**
+ * This test sends two messages receives on of them but doesn't ack it.
+ * The consumer is then closed
+ * the first message should be returned as redelivered.
+ * the second message should be delivered normally.
+ * @throws Exception
+ */
+ public void testSend2ThenCloseAfter1andTryAgain() throws Exception
+ {
+ assertTrue("session is not transacted", _session.getTransacted());
+ assertTrue("session is not transacted", _pubSession.getTransacted());
+
+ _logger.info("sending two test messages");
+ _publisher.send(_pubSession.createTextMessage("1"));
+ _publisher.send(_pubSession.createTextMessage("2"));
+ _pubSession.commit();
+
+ _logger.info("getting test message");
+ Message result = _consumer.receive(5000);
+
+ assertNotNull("Message received should not be null", result);
+ assertEquals("1", ((TextMessage) result).getText());
+ assertTrue("Messasge is marked as redelivered" + result, !result.getJMSRedelivered());
+
+ _logger.info("Closing Consumer");
+ _consumer.close();
+
+ _logger.info("Creating New consumer");
+ _consumer = _session.createConsumer(_jmsQueue);
+
+ _logger.info("receiving result");
+
+// NOTE: Both msg 1 & 2 will be marked as redelivered as they have both will have been rejected.
+// Only the occasion where it is not rejected will it mean it hasn't arrived at the client yet.
+ result = _consumer.receive(5000);
+ assertNotNull("test message was consumed and rolled back, but is gone", result);
+
+// The first message back will be either 1 or 2 being redelivered
+ if (result.getJMSRedelivered())
+ {
+ assertTrue("Messasge is not marked as redelivered" + result, result.getJMSRedelivered());
+ }
+ else // or it will be msg 2 arriving the first time due to latency.
+ {
+ _logger.info("Message 2 wasn't prefetched so wasn't rejected");
+ assertEquals("2", ((TextMessage) result).getText());
+ }
+
+ Message result2 = _consumer.receive(5000);
+ assertNotNull("test message was consumed and rolled back, but is gone", result2);
+
+ // if this is message 1 then it should be marked as redelivered
+ if("1".equals(((TextMessage) result2).getText()))
+ {
+ assertTrue("Messasge is not marked as redelivered" + result2, result2.getJMSRedelivered());
+ }
+
+ assertNotSame("Messages should not have the same content",((TextMessage) result2).getText(), ((TextMessage) result).getText() );
+
+ result = _consumer.receive(1000);
+ assertNull("test message should be null:" + result, result);
+
+ _session.commit();
+
+ }
+
+ public void testPutThenRollbackThenGet() throws Exception
+ {
+ assertTrue("session is not transacted", _session.getTransacted());
+ assertTrue("session is not transacted", _pubSession.getTransacted());
+
+ _logger.info("sending test message");
+ String MESSAGE_TEXT = "testPutThenRollbackThenGet";
+
+ _publisher.send(_pubSession.createTextMessage(MESSAGE_TEXT));
+ _pubSession.commit();
+
+ assertNotNull(_consumer.receive(5000));
+
+ _publisher.send(_pubSession.createTextMessage(MESSAGE_TEXT));
+
+ _logger.info("rolling back");
+ _pubSession.rollback();
+
+ _logger.info("receiving result");
+ Message result = _consumer.receive(5000);
+ assertNull("test message was put and rolled back, but is still present", result);
+
+ _publisher.send(_pubSession.createTextMessage(MESSAGE_TEXT));
+
+ _pubSession.commit();
+
+ assertNotNull(_consumer.receive(5000));
+
+ }
+
+}
diff --git a/Final/java/client/src/test/java/org/apache/qpid/test/unit/transacted/TransactedTest.java b/Final/java/client/src/test/java/org/apache/qpid/test/unit/transacted/TransactedTest.java
new file mode 100644
index 0000000000..678474a18b
--- /dev/null
+++ b/Final/java/client/src/test/java/org/apache/qpid/test/unit/transacted/TransactedTest.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.test.unit.transacted;
+
+import junit.framework.TestCase;
+
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.client.AMQQueue;
+import org.apache.qpid.client.AMQSession;
+import org.apache.qpid.client.transport.TransportConnection;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.jms.Session;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageProducer;
+import javax.jms.TextMessage;
+
+public class TransactedTest extends TestCase
+{
+ private AMQQueue queue1;
+ private AMQQueue queue2;
+
+ private AMQConnection con;
+ private Session session;
+ private MessageConsumer consumer1;
+ private MessageProducer producer2;
+
+ private AMQConnection prepCon;
+ private Session prepSession;
+ private MessageProducer prepProducer1;
+
+ private AMQConnection testCon;
+ private Session testSession;
+ private MessageConsumer testConsumer1;
+ private MessageConsumer testConsumer2;
+ private static final Logger _logger = LoggerFactory.getLogger(TransactedTest.class);
+
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+ TransportConnection.createVMBroker(1);
+ _logger.info("Create Connection");
+ con = new AMQConnection("vm://:1", "guest", "guest", "TransactedTest", "test");
+
+ _logger.info("Create Session");
+ session = con.createSession(true, Session.SESSION_TRANSACTED);
+ _logger.info("Create Q1");
+ queue1 =
+ new AMQQueue(session.getDefaultQueueExchangeName(), new AMQShortString("Q1"), new AMQShortString("Q1"), false,
+ true);
+ _logger.info("Create Q2");
+ queue2 = new AMQQueue(session.getDefaultQueueExchangeName(), new AMQShortString("Q2"), false);
+
+ _logger.info("Create Consumer of Q1");
+ consumer1 = session.createConsumer(queue1);
+ // Dummy just to create the queue.
+ _logger.info("Create Consumer of Q2");
+ MessageConsumer consumer2 = session.createConsumer(queue2);
+ _logger.info("Close Consumer of Q2");
+ consumer2.close();
+
+ _logger.info("Create producer to Q2");
+ producer2 = session.createProducer(queue2);
+
+ _logger.info("Start Connection");
+ con.start();
+
+ _logger.info("Create prep connection");
+ prepCon = new AMQConnection("vm://:1", "guest", "guest", "PrepConnection", "test");
+
+ _logger.info("Create prep session");
+ prepSession = prepCon.createSession(false, AMQSession.NO_ACKNOWLEDGE);
+
+ _logger.info("Create prep producer to Q1");
+ prepProducer1 = prepSession.createProducer(queue1);
+
+ _logger.info("Create prep connection start");
+ prepCon.start();
+
+ _logger.info("Create test connection");
+ testCon = new AMQConnection("vm://:1", "guest", "guest", "TestConnection", "test");
+ _logger.info("Create test session");
+ testSession = testCon.createSession(false, AMQSession.NO_ACKNOWLEDGE);
+ _logger.info("Create test consumer of q2");
+ testConsumer2 = testSession.createConsumer(queue2);
+ }
+
+ protected void tearDown() throws Exception
+ {
+ _logger.info("Close connection");
+ con.close();
+ _logger.info("Close test connection");
+ testCon.close();
+ _logger.info("Close prep connection");
+ prepCon.close();
+ _logger.info("Kill broker");
+ TransportConnection.killAllVMBrokers();
+ super.tearDown();
+ }
+
+ public void testCommit() throws Exception
+ {
+ // add some messages
+ _logger.info("Send prep A");
+ prepProducer1.send(prepSession.createTextMessage("A"));
+ _logger.info("Send prep B");
+ prepProducer1.send(prepSession.createTextMessage("B"));
+ _logger.info("Send prep C");
+ prepProducer1.send(prepSession.createTextMessage("C"));
+
+ // send and receive some messages
+ _logger.info("Send X to Q2");
+ producer2.send(session.createTextMessage("X"));
+ _logger.info("Send Y to Q2");
+ producer2.send(session.createTextMessage("Y"));
+ _logger.info("Send Z to Q2");
+ producer2.send(session.createTextMessage("Z"));
+
+ _logger.info("Read A from Q1");
+ expect("A", consumer1.receive(1000));
+ _logger.info("Read B from Q1");
+ expect("B", consumer1.receive(1000));
+ _logger.info("Read C from Q1");
+ expect("C", consumer1.receive(1000));
+
+ // commit
+ _logger.info("session commit");
+ session.commit();
+ _logger.info("Start test Connection");
+ testCon.start();
+
+ // ensure sent messages can be received and received messages are gone
+ _logger.info("Read X from Q2");
+ expect("X", testConsumer2.receive(1000));
+ _logger.info("Read Y from Q2");
+ expect("Y", testConsumer2.receive(1000));
+ _logger.info("Read Z from Q2");
+ expect("Z", testConsumer2.receive(1000));
+
+ _logger.info("create test session on Q1");
+ testConsumer1 = testSession.createConsumer(queue1);
+ _logger.info("Read null from Q1");
+ assertTrue(null == testConsumer1.receive(1000));
+ _logger.info("Read null from Q2");
+ assertTrue(null == testConsumer2.receive(1000));
+ }
+
+ public void testRollback() throws Exception
+ {
+ // add some messages
+ _logger.info("Send prep RB_A");
+ prepProducer1.send(prepSession.createTextMessage("RB_A"));
+ _logger.info("Send prep RB_B");
+ prepProducer1.send(prepSession.createTextMessage("RB_B"));
+ _logger.info("Send prep RB_C");
+ prepProducer1.send(prepSession.createTextMessage("RB_C"));
+
+ _logger.info("Sending RB_X RB_Y RB_Z");
+ producer2.send(session.createTextMessage("RB_X"));
+ producer2.send(session.createTextMessage("RB_Y"));
+ producer2.send(session.createTextMessage("RB_Z"));
+ _logger.info("Receiving RB_A RB_B");
+ expect("RB_A", consumer1.receive(1000));
+ expect("RB_B", consumer1.receive(1000));
+ // Don't consume 'RB_C' leave it in the prefetch cache to ensure rollback removes it.
+ // Quick sleep to ensure 'RB_C' gets pre-fetched
+ Thread.sleep(500);
+
+ // rollback
+ _logger.info("rollback");
+ session.rollback();
+
+ _logger.info("Receiving RB_A RB_B RB_C");
+ // ensure sent messages are not visible and received messages are requeued
+ expect("RB_A", consumer1.receive(1000), true);
+ expect("RB_B", consumer1.receive(1000), true);
+ expect("RB_C", consumer1.receive(1000), true);
+
+ _logger.info("Starting new connection");
+ testCon.start();
+ testConsumer1 = testSession.createConsumer(queue1);
+ _logger.info("Testing we have no messages left");
+ assertTrue(null == testConsumer1.receive(1000));
+ assertTrue(null == testConsumer2.receive(1000));
+
+ session.commit();
+
+ _logger.info("Testing we have no messages left after commit");
+ assertTrue(null == testConsumer1.receive(1000));
+ assertTrue(null == testConsumer2.receive(1000));
+ }
+
+ public void testResendsMsgsAfterSessionClose() throws Exception
+ {
+ AMQConnection con = new AMQConnection("vm://:1", "guest", "guest", "consumer1", "test");
+
+ Session consumerSession = con.createSession(true, Session.SESSION_TRANSACTED);
+ AMQQueue queue3 = new AMQQueue(consumerSession.getDefaultQueueExchangeName(), new AMQShortString("Q3"), false);
+ MessageConsumer consumer = consumerSession.createConsumer(queue3);
+
+ AMQConnection con2 = new AMQConnection("vm://:1", "guest", "guest", "producer1", "test");
+ Session producerSession = con2.createSession(true, Session.SESSION_TRANSACTED);
+ MessageProducer producer = producerSession.createProducer(queue3);
+
+ _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"));
+
+ producerSession.commit();
+
+ _logger.info("Starting connection");
+ con.start();
+ TextMessage tm = (TextMessage) consumer.receive();
+ assertNotNull(tm);
+ assertEquals("msg1", tm.getText());
+
+ consumerSession.commit();
+
+ _logger.info("Received and committed first message");
+ tm = (TextMessage) consumer.receive(1000);
+ assertNotNull(tm);
+ assertEquals("msg2", tm.getText());
+
+ tm = (TextMessage) consumer.receive(1000);
+ assertNotNull(tm);
+ assertEquals("msg3", tm.getText());
+
+ tm = (TextMessage) consumer.receive(1000);
+ assertNotNull(tm);
+ assertEquals("msg4", tm.getText());
+
+ _logger.info("Received all four messages. Closing connection with three outstanding messages");
+
+ consumerSession.close();
+
+ consumerSession = con.createSession(true, Session.SESSION_TRANSACTED);
+
+ consumer = consumerSession.createConsumer(queue3);
+
+ // no ack for last three messages so when I call recover I expect to get three messages back
+ tm = (TextMessage) consumer.receive(3000);
+ assertNotNull(tm);
+ assertEquals("msg2", tm.getText());
+ assertTrue("Message is not redelivered", tm.getJMSRedelivered());
+
+ tm = (TextMessage) consumer.receive(3000);
+ assertNotNull(tm);
+ assertEquals("msg3", tm.getText());
+ assertTrue("Message is not redelivered", tm.getJMSRedelivered());
+
+ tm = (TextMessage) consumer.receive(3000);
+ assertNotNull(tm);
+ assertEquals("msg4", tm.getText());
+ assertTrue("Message is not redelivered", tm.getJMSRedelivered());
+
+ _logger.info("Received redelivery of three messages. Committing");
+
+ consumerSession.commit();
+
+ _logger.info("Called commit");
+
+ tm = (TextMessage) consumer.receive(1000);
+ assertNull(tm);
+
+ _logger.info("No messages redelivered as is expected");
+
+ con.close();
+ con2.close();
+ }
+
+ private void expect(String text, Message msg) throws JMSException
+ {
+ expect(text, msg, false);
+ }
+
+ private void expect(String text, Message msg, boolean requeued) throws JMSException
+ {
+ assertNotNull("Message should not be null", msg);
+ assertTrue("Message should be a text message", msg instanceof TextMessage);
+ assertEquals("Message content does not match expected", text, ((TextMessage) msg).getText());
+ assertEquals("Message should " + (requeued ? "" : "not") + " be requeued", requeued, msg.getJMSRedelivered());
+ }
+
+ public static junit.framework.Test suite()
+ {
+ return new junit.framework.TestSuite(TransactedTest.class);
+ }
+}
diff --git a/Final/java/client/src/test/java/org/apache/qpid/testutil/Config.java b/Final/java/client/src/test/java/org/apache/qpid/testutil/Config.java
new file mode 100644
index 0000000000..b777cf93b6
--- /dev/null
+++ b/Final/java/client/src/test/java/org/apache/qpid/testutil/Config.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.testutil;
+
+import javax.jms.Connection;
+import javax.jms.Destination;
+
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.client.AMQHeadersExchange;
+import org.apache.qpid.client.AMQQueue;
+import org.apache.qpid.client.AMQTopic;
+import org.apache.qpid.exchange.ExchangeDefaults;
+
+public class Config
+{
+ public static final String QUEUE = "queue";
+ public static final String TOPIC = "topic";
+ public static final String HEADERS = "headers";
+
+ private String host = "localhost";
+ private int port = 5672;
+ private String type;
+ private String name = "simple_test_queue";
+
+ public Config()
+ {
+ this("localhost", 5672, QUEUE, "simple_test_queue");
+ }
+
+ public Config(String host, int port, String type, String name)
+ {
+ setHost(host);
+ setPort(port);
+ setType(type);
+ setName(name);
+ }
+
+ 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 getType()
+ {
+ return type;
+ }
+
+ public void setType(String type)
+ {
+ this.type = type;
+ }
+
+ public boolean isQueue()
+ {
+ return QUEUE.equalsIgnoreCase(type);
+ }
+
+ public boolean isTopic()
+ {
+ return TOPIC.equalsIgnoreCase(type);
+ }
+
+ private boolean isHeaders()
+ {
+ return HEADERS.equalsIgnoreCase(type);
+ }
+
+ public void setQueue(boolean queue)
+ {
+ type = queue ? QUEUE : TOPIC;
+ }
+
+ public String getName()
+ {
+ return name;
+ }
+
+ public void setName(String name)
+ {
+ this.name = name;
+ }
+
+ public Destination getDestination()
+ {
+ if(isQueue())
+ {
+ System.out.println("Using queue named " + name);
+ return new AMQQueue(ExchangeDefaults.DIRECT_EXCHANGE_NAME,name);
+ }
+ else if(isTopic())
+ {
+ System.out.println("Using topic named " + name);
+ return new AMQTopic(ExchangeDefaults.TOPIC_EXCHANGE_NAME,name);
+ }
+ else if(isHeaders())
+ {
+ System.out.println("Using headers exhange named " + name);
+ return new AMQHeadersExchange(name);
+ }
+ return null;
+ }
+
+ public Connection getConnection() throws Exception
+ {
+ System.out.println("Connecting to " + host + " on " + port + "...");
+ return new AMQConnection(host, port, "guest", "guest", "Client" + System.currentTimeMillis(), "/test");
+ }
+
+ public boolean setOptions(String[] argv)
+ {
+ try
+ {
+ for(int i = 0; i < argv.length - 1; i += 2)
+ {
+ String key = argv[i];
+ String value = argv[i+1];
+ setOption(key, value);
+ }
+ return true;
+ }
+ catch(Exception e)
+ {
+ System.out.println(e.getMessage());
+ }
+ return false;
+ }
+
+ private void setOption(String key, String value)
+ {
+ if("-host".equalsIgnoreCase(key))
+ {
+ setHost(value);
+ }
+ else if("-port".equalsIgnoreCase(key))
+ {
+ try
+ {
+ setPort(Integer.parseInt(value));
+ }
+ catch(NumberFormatException e)
+ {
+ throw new RuntimeException("Bad port number: " + value, e);
+ }
+ }
+ else if("-name".equalsIgnoreCase(key))
+ {
+ setName(value);
+ }
+ else if("-type".equalsIgnoreCase(key))
+ {
+ if(QUEUE.equalsIgnoreCase(value)
+ || TOPIC.equalsIgnoreCase(value)
+ || HEADERS.equalsIgnoreCase(value))
+ {
+ type = value;
+ }
+ else{
+ throw new RuntimeException("Bad destination type: " + value);
+ }
+ }
+ else
+ {
+ System.out.println("Ignoring unrecognised option: " + key);
+ }
+ }
+}
diff --git a/Final/java/client/src/test/java/org/apache/qpid/testutil/QpidClientConnection.java b/Final/java/client/src/test/java/org/apache/qpid/testutil/QpidClientConnection.java
new file mode 100644
index 0000000000..7eb2abe7eb
--- /dev/null
+++ b/Final/java/client/src/test/java/org/apache/qpid/testutil/QpidClientConnection.java
@@ -0,0 +1,287 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.qpid.testutil;
+
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.client.AMQConnectionFactory;
+import org.apache.qpid.client.AMQConnectionURL;
+import org.apache.qpid.client.JMSAMQException;
+import org.apache.qpid.url.URLSyntaxException;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+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.Queue;
+import javax.jms.Session;
+import javax.jms.TextMessage;
+
+public class QpidClientConnection implements ExceptionListener
+{
+ private static final Logger _logger = LoggerFactory.getLogger(QpidClientConnection.class);
+
+ private boolean transacted = true;
+ private int ackMode = Session.CLIENT_ACKNOWLEDGE;
+ private Connection connection;
+
+ private String virtualHost;
+ private String brokerlist;
+ private int prefetch;
+ protected Session session;
+ protected boolean connected;
+
+ public QpidClientConnection(String broker)
+ {
+ super();
+ setVirtualHost("/test");
+ setBrokerList(broker);
+ setPrefetch(5000);
+ }
+
+ public void connect() throws JMSException
+ {
+ if (!connected)
+ {
+ /*
+ * amqp://[user:pass@][clientid]/virtualhost?
+ * brokerlist='[transport://]host[:port][?option='value'[&option='value']];'
+ * [&failover='method[?option='value'[&option='value']]']
+ * [&option='value']"
+ */
+ String brokerUrl = "amqp://guest:guest@" + virtualHost + "?brokerlist='" + brokerlist + "'";
+ try
+ {
+ AMQConnectionFactory factory = new AMQConnectionFactory(new AMQConnectionURL(brokerUrl));
+ _logger.info("connecting to Qpid :" + brokerUrl);
+ connection = factory.createConnection();
+
+ // register exception listener
+ connection.setExceptionListener(this);
+
+ session = ((AMQConnection) connection).createSession(transacted, ackMode, prefetch);
+
+ _logger.info("starting connection");
+ connection.start();
+
+ connected = true;
+ }
+ catch (URLSyntaxException e)
+ {
+ throw new JMSAMQException("URL syntax error in [" + brokerUrl + "]: " + e.getMessage(), e);
+ }
+ }
+ }
+
+ public void disconnect() throws JMSException
+ {
+ if (connected)
+ {
+ session.commit();
+ session.close();
+ connection.close();
+ connected = false;
+ _logger.info("disconnected");
+ }
+ }
+
+ public void disconnectWithoutCommit() throws JMSException
+ {
+ if (connected)
+ {
+ session.close();
+ connection.close();
+ connected = false;
+ _logger.info("disconnected without commit");
+ }
+ }
+
+ public String getBrokerList()
+ {
+ return brokerlist;
+ }
+
+ public void setBrokerList(String brokerlist)
+ {
+ this.brokerlist = brokerlist;
+ }
+
+ public String getVirtualHost()
+ {
+ return virtualHost;
+ }
+
+ public void setVirtualHost(String virtualHost)
+ {
+ this.virtualHost = virtualHost;
+ }
+
+ public void setPrefetch(int prefetch)
+ {
+ this.prefetch = prefetch;
+ }
+
+ /** override as necessary */
+ public void onException(JMSException exception)
+ {
+ _logger.info("ExceptionListener event: error " + exception.getErrorCode() + ", message: " + exception.getMessage());
+ }
+
+ public boolean isConnected()
+ {
+ return connected;
+ }
+
+ public Session getSession()
+ {
+ return session;
+ }
+
+ /**
+ * Put a String as a text messages, repeat n times. A null payload will result in a null message.
+ *
+ * @param queueName The queue name to put to
+ * @param payload the content of the payload
+ * @param copies the number of messages to put
+ *
+ * @throws javax.jms.JMSException any exception that occurs
+ */
+ public void put(String queueName, String payload, int copies) throws JMSException
+ {
+ if (!connected)
+ {
+ connect();
+ }
+
+ _logger.info("putting to queue " + queueName);
+ Queue queue = session.createQueue(queueName);
+
+ final MessageProducer sender = session.createProducer(queue);
+
+ for (int i = 0; i < copies; i++)
+ {
+ Message m = session.createTextMessage(payload + i);
+ m.setIntProperty("index", i + 1);
+ sender.send(m);
+ }
+
+ session.commit();
+ sender.close();
+ _logger.info("put " + copies + " copies");
+ }
+
+ /**
+ * GET the top message on a queue. Consumes the message. Accepts timeout value.
+ *
+ * @param queueName The quename to get from
+ * @param readTimeout The timeout to use
+ *
+ * @return the content of the text message if any
+ *
+ * @throws javax.jms.JMSException any exception that occured
+ */
+ public Message getNextMessage(String queueName, long readTimeout) throws JMSException
+ {
+ if (!connected)
+ {
+ connect();
+ }
+
+ Queue queue = session.createQueue(queueName);
+
+ final MessageConsumer consumer = session.createConsumer(queue);
+
+ Message message = consumer.receive(readTimeout);
+ session.commit();
+ consumer.close();
+
+ Message result;
+
+ // all messages we consume should be TextMessages
+ if (message instanceof TextMessage)
+ {
+ result = ((TextMessage) message);
+ }
+ else if (null == message)
+ {
+ result = null;
+ }
+ else
+ {
+ _logger.info("warning: received non-text message");
+ result = message;
+ }
+
+ return result;
+ }
+
+ /**
+ * GET the top message on a queue. Consumes the message.
+ *
+ * @param queueName The Queuename to get from
+ *
+ * @return The string content of the text message, if any received
+ *
+ * @throws javax.jms.JMSException any exception that occurs
+ */
+ public Message getNextMessage(String queueName) throws JMSException
+ {
+ return getNextMessage(queueName, 0);
+ }
+
+ /**
+ * Completely clears a queue. For readTimeout behaviour see Javadocs for javax.jms.MessageConsumer.
+ *
+ * @param queueName The Queue name to consume from
+ * @param readTimeout The timeout for each consume
+ *
+ * @throws javax.jms.JMSException Any exception that occurs during the consume
+ * @throws InterruptedException If the consume thread was interrupted during a consume.
+ */
+ public void consume(String queueName, int readTimeout) throws JMSException, InterruptedException
+ {
+ if (!connected)
+ {
+ connect();
+ }
+
+ _logger.info("consuming queue " + queueName);
+ Queue queue = session.createQueue(queueName);
+
+ final MessageConsumer consumer = session.createConsumer(queue);
+ int messagesReceived = 0;
+
+ _logger.info("consuming...");
+ while ((consumer.receive(readTimeout)) != null)
+ {
+ messagesReceived++;
+ }
+
+ session.commit();
+ consumer.close();
+ _logger.info("consumed: " + messagesReceived);
+ }
+}
diff --git a/Final/java/client/src/test/java/org/apache/qpid/testutil/VMBrokerSetup.java b/Final/java/client/src/test/java/org/apache/qpid/testutil/VMBrokerSetup.java
new file mode 100644
index 0000000000..cedf1ac824
--- /dev/null
+++ b/Final/java/client/src/test/java/org/apache/qpid/testutil/VMBrokerSetup.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.testutil;
+
+import junit.extensions.TestSetup;
+import junit.framework.Test;
+
+import org.apache.qpid.client.transport.TransportConnection;
+
+public class VMBrokerSetup extends TestSetup
+{
+ public VMBrokerSetup(Test t)
+ {
+ super(t);
+ }
+
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+ try
+ {
+ TransportConnection.createVMBroker(1);
+ }
+ catch (Exception e)
+ {
+ fail("Unable to create broker: " + e);
+ }
+ }
+
+ protected void tearDown() throws Exception
+ {
+ TransportConnection.killVMBroker(1);
+ super.tearDown();
+ }
+}
diff --git a/Final/java/client/test/bin/IBM-JNDI-Setup.bat b/Final/java/client/test/bin/IBM-JNDI-Setup.bat
new file mode 100644
index 0000000000..eb6a87fa9e
--- /dev/null
+++ b/Final/java/client/test/bin/IBM-JNDI-Setup.bat
@@ -0,0 +1,69 @@
+@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 Java Broker
+
+set CMD="IBM-JNDI-Setup.bat"
+set JAVACLASS=
+
+rem Guess QPID_HOME if not defined
+set CURRENT_DIR=%cd%
+if not "%QPID_HOME%" == "" goto gotHome
+set QPID_HOME=%CURRENT_DIR%
+echo %QPID_HOME%
+if exist "%QPID_HOME%\bin\%CMD%" goto okHome
+cd ..
+set QPID_HOME=%cd%
+cd %CURRENT_DIR%
+:gotHome
+if exist "%QPID_HOME%\bin\%CMD%" goto okHome
+echo The QPID_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
+
+set CLIENT_TEST_CLASSES=%QPID_HOME%\lib\client-test-launch.jar
+
+echo on
+"%JAVA_HOME%\bin\java" -server -Xmx1024m -DQPID_HOME="%QPID_HOME%" -cp "%CLIENT_TEST_CLASSES%" org.apache.qpid.IBMPerfTest.JNDIBindConnectionFactory amqp://guest:guest@clientid/testpath?brokerlist='localhost' amq.ConnectionFactory
+"%JAVA_HOME%\bin\java" -server -Xmx1024m -DQPID_HOME="%QPID_HOME%" -cp "%CLIENT_TEST_CLASSES%" org.apache.qpid.IBMPerfTest.JNDIBindConnectionFactory amqp://guest:guest@clientid/testpath?brokerlist='vm://:1' amq.VMConnectionFactory
+"%JAVA_HOME%\bin\java" -server -Xmx1024m -DQPID_HOME="%QPID_HOME%" -cp "%CLIENT_TEST_CLASSES%" org.apache.qpid.IBMPerfTest.JNDIBindQueue amq.Queue direct://amq.direct//IBMPerfQueue1
+"%JAVA_HOME%\bin\java" -server -Xmx1024m -DQPID_HOME="%QPID_HOME%" -cp "%CLIENT_TEST_CLASSES%" org.apache.qpid.IBMPerfTest.JNDIBindTopic amq.Topic1 topic://amq.topic/IBMPerfTopic1/
+"%JAVA_HOME%\bin\java" -server -Xmx1024m -DQPID_HOME="%QPID_HOME%" -cp "%CLIENT_TEST_CLASSES%" org.apache.qpid.IBMPerfTest.JNDIBindTopic amq.Topic2 topic://amq.topic/IBMPerfTopic2/
+"%JAVA_HOME%\bin\java" -server -Xmx1024m -DQPID_HOME="%QPID_HOME%" -cp "%CLIENT_TEST_CLASSES%" org.apache.qpid.IBMPerfTest.JNDIBindTopic amq.Topic3 topic://amq.topic/IBMPerfTopic3/
+
+
+
+:end
+
+pause \ No newline at end of file
diff --git a/Final/java/client/test/bin/IBM-JNDI-Setup.sh b/Final/java/client/test/bin/IBM-JNDI-Setup.sh
new file mode 100755
index 0000000000..e3112f812d
--- /dev/null
+++ b/Final/java/client/test/bin/IBM-JNDI-Setup.sh
@@ -0,0 +1,27 @@
+#!/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.
+#
+
+qpid-run org.apache.qpid.IBMPerfTest.JNDIBindConnectionFactory amqp://guest:guest@clientid/testpath?brokerlist=\'tcp://localhost\' amq.ConnectionFactory
+qpid-run org.apache.qpid.IBMPerfTest.JNDIBindConnectionFactory amqp://guest:guest@clientid/testpath?brokerlist=\'vm://:1\' amq.VMConnectionFactory
+qpid-run org.apache.qpid.IBMPerfTest.JNDIBindQueue amq.Queue direct://amq.direct//IBMPerfQueue1
+qpid-run org.apache.qpid.IBMPerfTest.JNDIBindTopic amq.Topic1 topic://amq.topic/IBMPerfTopic1/
+qpid-run org.apache.qpid.IBMPerfTest.JNDIBindTopic amq.Topic2 topic://amq.topic/IBMPerfTopic2/
+qpid-run org.apache.qpid.IBMPerfTest.JNDIBindTopic amq.Topic3 topic://amq.topic/IBMPerfTopic3/
+qpid-run org.apache.qpid.IBMPerfTest.JNDIBindTopic amq.Topic4 topic://amq.topic/IBMPerfTopic4/ \ No newline at end of file
diff --git a/Final/java/client/test/bin/IBM-Publisher.bat b/Final/java/client/test/bin/IBM-Publisher.bat
new file mode 100644
index 0000000000..5bb4343c4c
--- /dev/null
+++ b/Final/java/client/test/bin/IBM-Publisher.bat
@@ -0,0 +1,62 @@
+@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 Java Broker
+
+set CMD="IBM-Publisher.bat"
+set JAVACLASS=JMSPerfHarness -pc JNDI -ii com.sun.jndi.fscontext.RefFSContextFactory -iu file:/C:/temp/IBMPerfTestsJNDI/ -cf amq.ConnectionFactory -d amq.Topic -db 1 -dx 4 -tc jms.r11.Publisher -nt 4 %*
+
+rem Guess QPID_HOME if not defined
+set CURRENT_DIR=%cd%
+if not "%QPID_HOME%" == "" goto gotHome
+set QPID_HOME=%CURRENT_DIR%
+echo %QPID_HOME%
+if exist "%QPID_HOME%\bin\%CMD%" goto okHome
+cd ..
+set QPID_HOME=%cd%
+cd %CURRENT_DIR%
+:gotHome
+if exist "%QPID_HOME%\bin\%CMD%" goto okHome
+echo The QPID_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
+
+set CLIENT_TEST_CLASSES=%QPID_HOME%\lib\client-test-launch.jar
+
+echo on
+"%JAVA_HOME%\bin\java" -server -Xmx1024m -DQPID_HOME="%QPID_HOME%" -cp "%CLIENT_TEST_CLASSES%" %JAVACLASS%
+
+:end
+
+pause \ No newline at end of file
diff --git a/Final/java/client/test/bin/IBM-Publisher.sh b/Final/java/client/test/bin/IBM-Publisher.sh
new file mode 100755
index 0000000000..adecf040bc
--- /dev/null
+++ b/Final/java/client/test/bin/IBM-Publisher.sh
@@ -0,0 +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.
+#
+
+export MSGSIZE=100
+qpid-run JMSPerfHarness -pc JNDI -ii com.sun.jndi.fscontext.RefFSContextFactory -iu file:///tmp/IBMPerfTestsJNDI/ -cf amq.ConnectionFactory -d amq.Topic -db 1 -dx 4 -tc jms.r11.Publisher -nt 4 $* \ No newline at end of file
diff --git a/Final/java/client/test/bin/IBM-PutGet.bat b/Final/java/client/test/bin/IBM-PutGet.bat
new file mode 100644
index 0000000000..c4316f1256
--- /dev/null
+++ b/Final/java/client/test/bin/IBM-PutGet.bat
@@ -0,0 +1,62 @@
+@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 Java Broker
+
+set CMD="IBM-PutGet.bat"
+set JAVACLASS=JMSPerfHarness -pc JNDI -ii com.sun.jndi.fscontext.RefFSContextFactory -iu file:/C:/temp/IBMPerfTestsJNDI/ -cf amq.ConnectionFactory -d amq.Queue -tc jms.r11.PutGet -nt 6 %*
+
+rem Guess QPID_HOME if not defined
+set CURRENT_DIR=%cd%
+if not "%QPID_HOME%" == "" goto gotHome
+set QPID_HOME=%CURRENT_DIR%
+echo %QPID_HOME%
+if exist "%QPID_HOME%\bin\%CMD%" goto okHome
+cd ..
+set QPID_HOME=%cd%
+cd %CURRENT_DIR%
+:gotHome
+if exist "%QPID_HOME%\bin\%CMD%" goto okHome
+echo The QPID_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
+
+set CLIENT_TEST_CLASSES=%QPID_HOME%\lib\client-test-launch.jar
+
+echo on
+"%JAVA_HOME%\bin\java" -server -Xmx1024m -DQPID_HOME="%QPID_HOME%" -cp "%CLIENT_TEST_CLASSES%" %JAVACLASS%
+
+:end
+
+pause \ No newline at end of file
diff --git a/Final/java/client/test/bin/IBM-PutGet.sh b/Final/java/client/test/bin/IBM-PutGet.sh
new file mode 100755
index 0000000000..c75667c9f6
--- /dev/null
+++ b/Final/java/client/test/bin/IBM-PutGet.sh
@@ -0,0 +1,21 @@
+#!/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.
+#
+
+qpid-run JMSPerfHarness -pc JNDI -ii com.sun.jndi.fscontext.RefFSContextFactory -iu file:///tmp/IBMPerfTestsJNDI/ -cf amq.ConnectionFactory -d amq.Queue -tc jms.r11.PutGet -nt 6 $* \ No newline at end of file
diff --git a/Final/java/client/test/bin/IBM-README.txt b/Final/java/client/test/bin/IBM-README.txt
new file mode 100644
index 0000000000..b076f3b3ca
--- /dev/null
+++ b/Final/java/client/test/bin/IBM-README.txt
@@ -0,0 +1,19 @@
+The IBM JMS Performance Harness scripts have take the following additional parameters
+
+-tx : Enable transactions
+-pp : Enable persistent messaging
+
+-ms 1000 : Set message size (default 1000 bytes)
+-cc 1 : Number of messages to per commit (default 1) Only applies to Sender/Subscriber
+
+The IBM JMS Performance Harness will need to be downloaded and the library added to client/test/lib.
+
+The Library can be found here:
+
+http://www.alphaworks.ibm.com/tech/perfharness
+
+Before running the required test the IBM JNDI Setup script should be run.
+
+This will create a filesystem based JNDI Context located at:
+
+System.properties{java.io.tmpdir}/IBMPerfTestsJNDI/ \ No newline at end of file
diff --git a/Final/java/client/test/bin/IBM-Receiver.bat b/Final/java/client/test/bin/IBM-Receiver.bat
new file mode 100644
index 0000000000..dff44d472a
--- /dev/null
+++ b/Final/java/client/test/bin/IBM-Receiver.bat
@@ -0,0 +1,62 @@
+@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 Java Broker
+
+set CMD="IBM-Receiver.bat"
+set JAVACLASS=JMSPerfHarness -pc JNDI -ii com.sun.jndi.fscontext.RefFSContextFactory -iu file:/C:/temp/IBMPerfTestsJNDI/ -cf amq.ConnectionFactory -d amq.Queue -tc jms.r11.Receiver %*
+
+rem Guess QPID_HOME if not defined
+set CURRENT_DIR=%cd%
+if not "%QPID_HOME%" == "" goto gotHome
+set QPID_HOME=%CURRENT_DIR%
+echo %QPID_HOME%
+if exist "%QPID_HOME%\bin\%CMD%" goto okHome
+cd ..
+set QPID_HOME=%cd%
+cd %CURRENT_DIR%
+:gotHome
+if exist "%QPID_HOME%\bin\%CMD%" goto okHome
+echo The QPID_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
+
+set CLIENT_TEST_CLASSES=%QPID_HOME%\lib\client-test-launch.jar
+
+echo on
+"%JAVA_HOME%\bin\java" -server -Xmx1024m -DQPID_HOME="%QPID_HOME%" -cp "%CLIENT_TEST_CLASSES%" %JAVACLASS%
+
+:end
+
+pause \ No newline at end of file
diff --git a/Final/java/client/test/bin/IBM-Receiver.sh b/Final/java/client/test/bin/IBM-Receiver.sh
new file mode 100755
index 0000000000..f50f0f744e
--- /dev/null
+++ b/Final/java/client/test/bin/IBM-Receiver.sh
@@ -0,0 +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.
+#
+
+export MSGSIZE=100
+qpid-run JMSPerfHarness -pc JNDI -ii com.sun.jndi.fscontext.RefFSContextFactory -iu file:///tmp/IBMPerfTestsJNDI/ -cf amq.ConnectionFactory -d amq.Queue -tc jms.r11.Receiver $* \ No newline at end of file
diff --git a/Final/java/client/test/bin/IBM-Sender.bat b/Final/java/client/test/bin/IBM-Sender.bat
new file mode 100644
index 0000000000..b8826322e5
--- /dev/null
+++ b/Final/java/client/test/bin/IBM-Sender.bat
@@ -0,0 +1,62 @@
+@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 Java Broker
+
+set CMD="IBM-Sender.bat"
+set JAVACLASS=JMSPerfHarness -pc JNDI -ii com.sun.jndi.fscontext.RefFSContextFactory -iu file:/C:/temp/IBMPerfTestsJNDI/ -cf amq.ConnectionFactory -d amq.Queue -tc jms.r11.Sender -ms $MSGSIZE -mg 1000000 %*
+
+rem Guess QPID_HOME if not defined
+set CURRENT_DIR=%cd%
+if not "%QPID_HOME%" == "" goto gotHome
+set QPID_HOME=%CURRENT_DIR%
+echo %QPID_HOME%
+if exist "%QPID_HOME%\bin\%CMD%" goto okHome
+cd ..
+set QPID_HOME=%cd%
+cd %CURRENT_DIR%
+:gotHome
+if exist "%QPID_HOME%\bin\%CMD%" goto okHome
+echo The QPID_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
+
+set CLIENT_TEST_CLASSES=%QPID_HOME%\lib\client-test-launch.jar
+
+echo on
+"%JAVA_HOME%\bin\java" -server -Xmx1024m -DQPID_HOME="%QPID_HOME%" -cp "%CLIENT_TEST_CLASSES%" %JAVACLASS%
+
+:end
+
+pause \ No newline at end of file
diff --git a/Final/java/client/test/bin/IBM-Sender.sh b/Final/java/client/test/bin/IBM-Sender.sh
new file mode 100755
index 0000000000..b99429fd54
--- /dev/null
+++ b/Final/java/client/test/bin/IBM-Sender.sh
@@ -0,0 +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.
+#
+
+export MSGSIZE=100
+qpid-run JMSPerfHarness -pc JNDI -ii com.sun.jndi.fscontext.RefFSContextFactory -iu file:///tmp/IBMPerfTestsJNDI/ -cf amq.ConnectionFactory -d amq.Queue -tc jms.r11.Sender -ms $MSGSIZE -mg 1000000 $* \ No newline at end of file
diff --git a/Final/java/client/test/bin/IBM-Subscriber.bat b/Final/java/client/test/bin/IBM-Subscriber.bat
new file mode 100644
index 0000000000..5245639eba
--- /dev/null
+++ b/Final/java/client/test/bin/IBM-Subscriber.bat
@@ -0,0 +1,62 @@
+@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 Java Broker
+
+set CMD="IBM-Subscriber.bat"
+set JAVACLASS=JMSPerfHarness -pc JNDI -ii com.sun.jndi.fscontext.RefFSContextFactory -iu file:/C:/temp/IBMPerfTestsJNDI/ -cf amq.ConnectionFactory -d amq.Topic -db 1 -dx 4 -tc jms.r11.Subscriber -nt 4 %*
+
+rem Guess QPID_HOME if not defined
+set CURRENT_DIR=%cd%
+if not "%QPID_HOME%" == "" goto gotHome
+set QPID_HOME=%CURRENT_DIR%
+echo %QPID_HOME%
+if exist "%QPID_HOME%\bin\%CMD%" goto okHome
+cd ..
+set QPID_HOME=%cd%
+cd %CURRENT_DIR%
+:gotHome
+if exist "%QPID_HOME%\bin\%CMD%" goto okHome
+echo The QPID_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
+
+set CLIENT_TEST_CLASSES=%QPID_HOME%\lib\client-test-launch.jar
+
+echo on
+"%JAVA_HOME%\bin\java" -server -Xmx1024m -DQPID_HOME="%QPID_HOME%" -cp "%CLIENT_TEST_CLASSES%" %JAVACLASS%
+
+:end
+
+pause \ No newline at end of file
diff --git a/Final/java/client/test/bin/IBM-Subscriber.sh b/Final/java/client/test/bin/IBM-Subscriber.sh
new file mode 100755
index 0000000000..43550100be
--- /dev/null
+++ b/Final/java/client/test/bin/IBM-Subscriber.sh
@@ -0,0 +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.
+#
+
+export MSGSIZE=100
+qpid-run JMSPerfHarness -pc JNDI -ii com.sun.jndi.fscontext.RefFSContextFactory -iu file:///tmp/IBMPerfTestsJNDI/ -cf amq.ConnectionFactory -d amq.Topic -db 1 -dx 4 -tc jms.r11.Subscriber -nt 4 $* \ No newline at end of file
diff --git a/Final/java/client/test/bin/headersListener.sh b/Final/java/client/test/bin/headersListener.sh
new file mode 100755
index 0000000000..81930b7043
--- /dev/null
+++ b/Final/java/client/test/bin/headersListener.sh
@@ -0,0 +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.
+#
+
+
+. qpid-run -Damqj.logging.level="INFO" org.apache.qpid.headers.Listener $*
diff --git a/Final/java/client/test/bin/headersListenerGroup.sh b/Final/java/client/test/bin/headersListenerGroup.sh
new file mode 100755
index 0000000000..e1cc05cfd2
--- /dev/null
+++ b/Final/java/client/test/bin/headersListenerGroup.sh
@@ -0,0 +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.
+#
+
+
+for i; do
+ ./headersListener.sh -host 10.0.0.1 -port 5672 >$i.out 2>$i.err &
+ echo $! > $i.pid
+done;
diff --git a/Final/java/client/test/bin/headersPublisher.sh b/Final/java/client/test/bin/headersPublisher.sh
new file mode 100755
index 0000000000..fd9fd26416
--- /dev/null
+++ b/Final/java/client/test/bin/headersPublisher.sh
@@ -0,0 +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.
+#
+
+
+. qpid-run -Damqj.logging.level="INFO" org.apache.qpid.headers.Publisher $*
diff --git a/Final/java/client/test/bin/run_many.sh b/Final/java/client/test/bin/run_many.sh
new file mode 100755
index 0000000000..cca2ffec21
--- /dev/null
+++ b/Final/java/client/test/bin/run_many.sh
@@ -0,0 +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.
+#
+
+
+# args:
+# <number of processes to start>
+# <name of run>
+# <command ro run>
+
+for i in `seq 1 $1`; do
+ $3 >$2.$i.out 2>>$2.err &
+ echo $! > $2.$i.pid
+done;
diff --git a/Final/java/client/test/bin/serviceProvidingClient.sh b/Final/java/client/test/bin/serviceProvidingClient.sh
new file mode 100755
index 0000000000..cbcf5a0f4b
--- /dev/null
+++ b/Final/java/client/test/bin/serviceProvidingClient.sh
@@ -0,0 +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.
+#
+
+PROFILE=$1
+shift
+# XXX -Xms1024m -XX:NewSize=300m
+. qpid-run org.apache.qpid.requestreply1.ServiceProvidingClient $1 guest guest /test serviceQ
diff --git a/Final/java/client/test/bin/serviceRequestingClient.sh b/Final/java/client/test/bin/serviceRequestingClient.sh
new file mode 100755
index 0000000000..213f44c00b
--- /dev/null
+++ b/Final/java/client/test/bin/serviceRequestingClient.sh
@@ -0,0 +1,27 @@
+#!/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.
+#
+
+PROFILE=$1
+shift
+thehosts=$1
+shift
+echo $thehosts
+# XXX -Xms1024m -XX:NewSize=300m
+. qpid-run -Damqj.logging.level="INFO" org.apache.qpid.requestreply1.ServiceRequestingClient $thehosts guest guest /test serviceQ "$@"
diff --git a/Final/java/client/test/bin/testService.sh b/Final/java/client/test/bin/testService.sh
new file mode 100755
index 0000000000..20161c3abf
--- /dev/null
+++ b/Final/java/client/test/bin/testService.sh
@@ -0,0 +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.
+#
+
+
+. qpid-run org.apache.qpid.requestreply1.TestService 192.168.55.63 5672 foo x x
diff --git a/Final/java/client/test/bin/topicListener.sh b/Final/java/client/test/bin/topicListener.sh
new file mode 100755
index 0000000000..ac0cb63c91
--- /dev/null
+++ b/Final/java/client/test/bin/topicListener.sh
@@ -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.
+#
+
+
+# XXX -Xmx512m -Xms512m -XX:NewSize=150m
+. qpid-run -Damqj.logging.level="INFO" org.apache.qpid.topic.Listener $*
diff --git a/Final/java/client/test/bin/topicPublisher.sh b/Final/java/client/test/bin/topicPublisher.sh
new file mode 100755
index 0000000000..e35c131fe8
--- /dev/null
+++ b/Final/java/client/test/bin/topicPublisher.sh
@@ -0,0 +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.
+#
+
+# XXX -Xmx512m -Xms512m -XX:NewSize=150m
+. qpid-run -Damqj.logging.level="INFO" org.apache.qpid.topic.Publisher $*
diff --git a/Final/java/client/test/etc/ApacheDS.properties b/Final/java/client/test/etc/ApacheDS.properties
new file mode 100644
index 0000000000..6c5cb4cec4
--- /dev/null
+++ b/Final/java/client/test/etc/ApacheDS.properties
@@ -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.
+#
+# Standard JNDI properties
+java.naming.factory.initial=com.sun.jndi.ldap.LdapCtxFactory
+java.naming.provider.url=ldap://localhost:389/ou=system
+java.naming.security.authentication=simple
+java.naming.security.principal=uid=admin,ou=system
+java.naming.security.credentials=secret
diff --git a/Final/java/client/test/example_build.xml b/Final/java/client/test/example_build.xml
new file mode 100644
index 0000000000..a12862be04
--- /dev/null
+++ b/Final/java/client/test/example_build.xml
@@ -0,0 +1,104 @@
+<?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.
+ -
+ -->
+
+<!-- example Blaze Component Java build file -->
+
+<project name="example-client" default="jar" basedir=".">
+ <property name="lib" value="${basedir}/lib"/>
+ <property name="common.lib" value="${basedir}/../common/lib"/>
+ <property name="example.dir" value="${basedir}"/>
+ <property name="example.src" value="${example.dir}/src"/>
+ <property name="example.lib" value="${example.dir}/lib"/>
+ <property name="example.tests" value="${example.dir}/test"/>
+ <property name="example.classes" value="${example.dir}/classes"/>
+ <property name="dist" value="${basedir}/dist"/>
+ <property name="dam.dist" value="${basedir}/damPackage"/>
+
+ <!-- Setup details -->
+ <target name="init">
+ <tstamp>
+ <format property="release" pattern="-dMMMyy" locale="en" timezone="GMT"/>
+ </tstamp>
+ <mkdir dir="${example.classes}"/>
+ </target>
+
+ <path id="example.classpath">
+ <fileset dir="${common}/lib">
+ <include name="**/*.jar"/>
+ </fileset>
+ <pathelement path="${example.classes}"/>
+ </path>
+
+ <!-- Remove all built files -->
+ <target name="clean" depends="init">
+ <delete dir="${example.classes}"/>
+ </target>
+
+ <path id="example_amq.classpath">
+ <fileset dir="${basedir}/lib">
+ <include name="**/*.jar"/>
+ </fileset>
+ <fileset dir="${example.lib}">
+ <include name="**/*.jar"/>
+ </fileset>
+ <pathelement path="${example.classes}"/>
+
+ </path>
+
+ <!-- Compile Java -->
+ <target name="compile" depends="init">
+ <javac destdir="${example.classes}" debug="on">
+ <classpath refid="example_amq.classpath"/>
+ <src path="${example.src}"/>
+ <exclude name="**/Test*.java"/>
+ </javac>
+
+ <copy todir="${example.classes}">
+ <!-- copy any non java src files into the build tree, e.g. log4j.properties -->
+ <fileset dir="${example.src}">
+ <exclude name="**/*.java"/>
+ <exclude name="**/package.html"/>
+ </fileset>
+ </copy>
+ </target>
+
+ <!-- Compile and build jar archive -->
+ <target name="dist" depends="compile">
+ <mkdir dir="${dist}"/>
+ <jar basedir="${example.classes}" jarfile="${dist}/example_amq.jar"/>
+ </target>
+
+ <!-- Create release zip and tar -->
+ <target name="release" depends="dist" description="Create a release package">
+
+ <zip destfile="${dist}/example_client.zip">
+ <zipfileset prefix="lib" file="${dist}/example_amq.jar" />
+ </zip>
+
+ <tar destfile="${dist}/example_client.tar.gz" compression="gzip">
+ <tarfileset prefix="lib" file="${dist}/example_amq.jar" />
+ </tar>
+ </target>
+
+
+
+</project>