From 1db5a8a2329ec064d1683294ee1a3d8d233de42d Mon Sep 17 00:00:00 2001 From: Stephen Vinoski Date: Sat, 18 Nov 2006 02:12:32 +0000 Subject: directory moves required for maven merge git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk/qpid@476414 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/server/AMQChannel.java | 788 +++++++++++++++++++ .../qpid/server/ConsumerTagNotUniqueException.java | 25 + .../src/main/java/org/apache/qpid/server/Main.java | 627 +++++++++++++++ .../org/apache/qpid/server/ManagedChannel.java | 67 ++ .../qpid/server/RequiredDeliveryException.java | 112 +++ .../java/org/apache/qpid/server/ack/TxAck.java | 132 ++++ .../qpid/server/ack/UnacknowledgedMessage.java | 51 ++ .../qpid/server/ack/UnacknowledgedMessageMap.java | 30 + .../server/ack/UnacknowledgedMessageMapImpl.java | 84 ++ .../qpid/server/configuration/Configurator.java | 105 +++ .../configuration/VirtualHostConfiguration.java | 220 ++++++ .../qpid/server/exchange/AbstractExchange.java | 139 ++++ .../server/exchange/DefaultExchangeFactory.java | 66 ++ .../server/exchange/DefaultExchangeRegistry.java | 95 +++ .../qpid/server/exchange/DestNameExchange.java | 223 ++++++ .../qpid/server/exchange/DestWildExchange.java | 226 ++++++ .../org/apache/qpid/server/exchange/Exchange.java | 50 ++ .../qpid/server/exchange/ExchangeFactory.java | 31 + .../server/exchange/ExchangeInUseException.java | 31 + .../qpid/server/exchange/ExchangeRegistry.java | 41 + .../qpid/server/exchange/HeadersBinding.java | 145 ++++ .../qpid/server/exchange/HeadersExchange.java | 271 +++++++ .../org/apache/qpid/server/exchange/Index.java | 88 +++ .../qpid/server/exchange/ManagedExchange.java | 93 +++ .../apache/qpid/server/exchange/MessageRouter.java | 39 + .../qpid/server/exchange/NoRouteException.java | 42 + .../qpid/server/handler/BasicAckMethodHandler.java | 55 ++ .../server/handler/BasicCancelMethodHandler.java | 61 ++ .../server/handler/BasicConsumeMethodHandler.java | 93 +++ .../server/handler/BasicPublishMethodHandler.java | 80 ++ .../qpid/server/handler/BasicQosHandler.java | 49 ++ .../server/handler/BasicRecoverMethodHandler.java | 57 ++ .../qpid/server/handler/ChannelCloseHandler.java | 61 ++ .../qpid/server/handler/ChannelCloseOkHandler.java | 54 ++ .../qpid/server/handler/ChannelFlowHandler.java | 64 ++ .../qpid/server/handler/ChannelOpenHandler.java | 61 ++ .../handler/ConnectionCloseMethodHandler.java | 68 ++ .../handler/ConnectionCloseOkMethodHandler.java | 66 ++ .../handler/ConnectionOpenMethodHandler.java | 71 ++ .../handler/ConnectionSecureOkMethodHandler.java | 118 +++ .../handler/ConnectionStartOkMethodHandler.java | 130 +++ .../handler/ConnectionTuneOkMethodHandler.java | 57 ++ .../server/handler/ExchangeDeclareHandler.java | 82 ++ .../qpid/server/handler/ExchangeDeleteHandler.java | 65 ++ .../server/handler/OnCurrentThreadExecutor.java | 34 + .../qpid/server/handler/QueueBindHandler.java | 97 +++ .../qpid/server/handler/QueueDeclareHandler.java | 127 +++ .../qpid/server/handler/QueueDeleteHandler.java | 87 +++ .../qpid/server/handler/TxCommitHandler.java | 61 ++ .../qpid/server/handler/TxRollbackHandler.java | 62 ++ .../qpid/server/handler/TxSelectHandler.java | 53 ++ .../org/apache/qpid/server/jms/JmsConsumer.java | 110 +++ .../qpid/server/management/AMQManagedObject.java | 97 +++ .../server/management/DefaultManagedObject.java | 171 ++++ .../management/JMXManagedObjectRegistry.java | 52 ++ .../qpid/server/management/MBeanAttribute.java | 42 + .../qpid/server/management/MBeanConstructor.java | 40 + .../qpid/server/management/MBeanDescription.java | 39 + .../qpid/server/management/MBeanIntrospector.java | 388 +++++++++ .../qpid/server/management/MBeanOperation.java | 43 + .../server/management/MBeanOperationParameter.java | 38 + .../apache/qpid/server/management/Managable.java | 34 + .../qpid/server/management/ManagedBroker.java | 98 +++ .../qpid/server/management/ManagedObject.java | 58 ++ .../server/management/ManagedObjectRegistry.java | 42 + .../server/management/ManagementConfiguration.java | 30 + .../management/NoopManagedObjectRegistry.java | 48 ++ .../qpid/server/protocol/AMQMethodEvent.java | 65 ++ .../qpid/server/protocol/AMQMethodListener.java | 55 ++ .../server/protocol/AMQMinaProtocolSession.java | 700 +++++++++++++++++ .../server/protocol/AMQPFastProtocolHandler.java | 230 ++++++ .../qpid/server/protocol/AMQPProtocolProvider.java | 53 ++ .../qpid/server/protocol/AMQProtocolSession.java | 125 +++ .../qpid/server/protocol/ExchangeInitialiser.java | 41 + .../qpid/server/protocol/HeartbeatConfig.java | 67 ++ .../qpid/server/protocol/ManagedConnection.java | 141 ++++ .../org/apache/qpid/server/queue/AMQMessage.java | 368 +++++++++ .../org/apache/qpid/server/queue/AMQQueue.java | 867 +++++++++++++++++++++ .../qpid/server/queue/AsyncDeliveryConfig.java | 56 ++ .../server/queue/ConcurrentDeliveryManager.java | 348 +++++++++ .../qpid/server/queue/DefaultQueueRegistry.java | 50 ++ .../apache/qpid/server/queue/DeliveryManager.java | 76 ++ .../apache/qpid/server/queue/ExchangeBindings.java | 112 +++ .../qpid/server/queue/FailedDequeueException.java | 39 + .../org/apache/qpid/server/queue/ManagedQueue.java | 220 ++++++ .../qpid/server/queue/MessageCleanupException.java | 35 + .../qpid/server/queue/NoConsumersException.java | 57 ++ .../apache/qpid/server/queue/QueueRegistry.java | 33 + .../org/apache/qpid/server/queue/Subscription.java | 32 + .../qpid/server/queue/SubscriptionFactory.java | 40 + .../apache/qpid/server/queue/SubscriptionImpl.java | 191 +++++ .../qpid/server/queue/SubscriptionManager.java | 31 + .../apache/qpid/server/queue/SubscriptionSet.java | 183 +++++ .../server/queue/SynchronizedDeliveryManager.java | 255 ++++++ .../server/queue/WeightedSubscriptionManager.java | 26 + .../qpid/server/registry/ApplicationRegistry.java | 200 +++++ .../ConfigurationFileApplicationRegistry.java | 158 ++++ .../qpid/server/registry/IApplicationRegistry.java | 68 ++ .../security/auth/AuthenticationManager.java | 33 + .../auth/AuthenticationProviderInitialiser.java | 66 ++ .../server/security/auth/AuthenticationResult.java | 43 + .../server/security/auth/CRAMMD5Initialiser.java | 38 + .../qpid/server/security/auth/JCAProvider.java | 46 ++ .../security/auth/NullAuthenticationManager.java | 85 ++ .../auth/PasswordFilePrincipalDatabase.java | 133 ++++ .../server/security/auth/PrincipalDatabase.java | 45 ++ .../security/auth/SASLAuthenticationManager.java | 227 ++++++ .../security/auth/UsernamePasswordInitialiser.java | 102 +++ .../server/security/auth/UsernamePrincipal.java | 42 + .../auth/amqplain/AmqPlainInitialiser.java | 38 + .../security/auth/amqplain/AmqPlainSaslServer.java | 123 +++ .../auth/amqplain/AmqPlainSaslServerFactory.java | 59 ++ .../security/auth/plain/PlainInitialiser.java | 38 + .../security/auth/plain/PlainSaslServer.java | 144 ++++ .../auth/plain/PlainSaslServerFactory.java | 59 ++ .../org/apache/qpid/server/state/AMQState.java | 36 + .../apache/qpid/server/state/AMQStateManager.java | 222 ++++++ .../state/IllegalStateTransitionException.java | 48 ++ .../server/state/StateAwareMethodListener.java | 40 + .../apache/qpid/server/state/StateListener.java | 30 + .../qpid/server/store/MemoryMessageStore.java | 145 ++++ .../org/apache/qpid/server/store/MessageStore.java | 83 ++ .../server/transport/ConnectorConfiguration.java | 86 ++ .../qpid/server/transport/ThreadPoolFilter.java | 695 +++++++++++++++++ .../java/org/apache/qpid/server/txn/TxnBuffer.java | 123 +++ .../java/org/apache/qpid/server/txn/TxnOp.java | 54 ++ .../apache/qpid/server/util/CircularBuffer.java | 126 +++ .../server/util/ConcurrentLinkedQueueNoSize.java | 38 + .../org/apache/qpid/server/util/LoggingProxy.java | 105 +++ .../qpid/server/util/NullApplicationRegistry.java | 109 +++ .../src/org/apache/qpid/server/AMQChannel.java | 788 ------------------- .../qpid/server/ConsumerTagNotUniqueException.java | 25 - java/broker/src/org/apache/qpid/server/Main.java | 627 --------------- .../src/org/apache/qpid/server/ManagedChannel.java | 67 -- .../qpid/server/RequiredDeliveryException.java | 112 --- .../src/org/apache/qpid/server/ack/TxAck.java | 132 ---- .../qpid/server/ack/UnacknowledgedMessage.java | 51 -- .../qpid/server/ack/UnacknowledgedMessageMap.java | 30 - .../server/ack/UnacknowledgedMessageMapImpl.java | 84 -- .../qpid/server/configuration/Configurator.java | 105 --- .../configuration/VirtualHostConfiguration.java | 220 ------ .../qpid/server/exchange/AbstractExchange.java | 139 ---- .../server/exchange/DefaultExchangeFactory.java | 66 -- .../server/exchange/DefaultExchangeRegistry.java | 95 --- .../qpid/server/exchange/DestNameExchange.java | 223 ------ .../qpid/server/exchange/DestWildExchange.java | 226 ------ .../org/apache/qpid/server/exchange/Exchange.java | 50 -- .../qpid/server/exchange/ExchangeFactory.java | 31 - .../server/exchange/ExchangeInUseException.java | 31 - .../qpid/server/exchange/ExchangeRegistry.java | 41 - .../qpid/server/exchange/HeadersBinding.java | 145 ---- .../qpid/server/exchange/HeadersExchange.java | 271 ------- .../src/org/apache/qpid/server/exchange/Index.java | 88 --- .../qpid/server/exchange/ManagedExchange.java | 93 --- .../apache/qpid/server/exchange/MessageRouter.java | 39 - .../qpid/server/exchange/NoRouteException.java | 42 - .../qpid/server/handler/BasicAckMethodHandler.java | 55 -- .../server/handler/BasicCancelMethodHandler.java | 61 -- .../server/handler/BasicConsumeMethodHandler.java | 93 --- .../server/handler/BasicPublishMethodHandler.java | 80 -- .../qpid/server/handler/BasicQosHandler.java | 49 -- .../server/handler/BasicRecoverMethodHandler.java | 57 -- .../qpid/server/handler/ChannelCloseHandler.java | 61 -- .../qpid/server/handler/ChannelCloseOkHandler.java | 54 -- .../qpid/server/handler/ChannelFlowHandler.java | 64 -- .../qpid/server/handler/ChannelOpenHandler.java | 61 -- .../handler/ConnectionCloseMethodHandler.java | 68 -- .../handler/ConnectionCloseOkMethodHandler.java | 66 -- .../handler/ConnectionOpenMethodHandler.java | 71 -- .../handler/ConnectionSecureOkMethodHandler.java | 118 --- .../handler/ConnectionStartOkMethodHandler.java | 130 --- .../handler/ConnectionTuneOkMethodHandler.java | 57 -- .../server/handler/ExchangeDeclareHandler.java | 82 -- .../qpid/server/handler/ExchangeDeleteHandler.java | 65 -- .../server/handler/OnCurrentThreadExecutor.java | 34 - .../qpid/server/handler/QueueBindHandler.java | 97 --- .../qpid/server/handler/QueueDeclareHandler.java | 127 --- .../qpid/server/handler/QueueDeleteHandler.java | 87 --- .../qpid/server/handler/TxCommitHandler.java | 61 -- .../qpid/server/handler/TxRollbackHandler.java | 62 -- .../qpid/server/handler/TxSelectHandler.java | 53 -- .../org/apache/qpid/server/jms/JmsConsumer.java | 110 --- .../qpid/server/management/AMQManagedObject.java | 97 --- .../server/management/DefaultManagedObject.java | 171 ---- .../management/JMXManagedObjectRegistry.java | 52 -- .../qpid/server/management/MBeanAttribute.java | 42 - .../qpid/server/management/MBeanConstructor.java | 40 - .../qpid/server/management/MBeanDescription.java | 39 - .../qpid/server/management/MBeanIntrospector.java | 388 --------- .../qpid/server/management/MBeanOperation.java | 43 - .../server/management/MBeanOperationParameter.java | 38 - .../apache/qpid/server/management/Managable.java | 34 - .../qpid/server/management/ManagedBroker.java | 98 --- .../qpid/server/management/ManagedObject.java | 58 -- .../server/management/ManagedObjectRegistry.java | 42 - .../server/management/ManagementConfiguration.java | 30 - .../management/NoopManagedObjectRegistry.java | 48 -- .../qpid/server/protocol/AMQMethodEvent.java | 65 -- .../qpid/server/protocol/AMQMethodListener.java | 55 -- .../server/protocol/AMQMinaProtocolSession.java | 700 ----------------- .../server/protocol/AMQPFastProtocolHandler.java | 230 ------ .../qpid/server/protocol/AMQPProtocolProvider.java | 53 -- .../qpid/server/protocol/AMQProtocolSession.java | 125 --- .../qpid/server/protocol/ExchangeInitialiser.java | 41 - .../qpid/server/protocol/HeartbeatConfig.java | 67 -- .../qpid/server/protocol/ManagedConnection.java | 141 ---- .../org/apache/qpid/server/queue/AMQMessage.java | 368 --------- .../src/org/apache/qpid/server/queue/AMQQueue.java | 867 --------------------- .../qpid/server/queue/AsyncDeliveryConfig.java | 56 -- .../server/queue/ConcurrentDeliveryManager.java | 348 --------- .../qpid/server/queue/DefaultQueueRegistry.java | 50 -- .../apache/qpid/server/queue/DeliveryManager.java | 76 -- .../apache/qpid/server/queue/ExchangeBindings.java | 112 --- .../qpid/server/queue/FailedDequeueException.java | 39 - .../org/apache/qpid/server/queue/ManagedQueue.java | 220 ------ .../qpid/server/queue/MessageCleanupException.java | 35 - .../qpid/server/queue/NoConsumersException.java | 57 -- .../apache/qpid/server/queue/QueueRegistry.java | 33 - .../org/apache/qpid/server/queue/Subscription.java | 32 - .../qpid/server/queue/SubscriptionFactory.java | 40 - .../apache/qpid/server/queue/SubscriptionImpl.java | 191 ----- .../qpid/server/queue/SubscriptionManager.java | 31 - .../apache/qpid/server/queue/SubscriptionSet.java | 183 ----- .../server/queue/SynchronizedDeliveryManager.java | 255 ------ .../server/queue/WeightedSubscriptionManager.java | 26 - .../qpid/server/registry/ApplicationRegistry.java | 200 ----- .../ConfigurationFileApplicationRegistry.java | 158 ---- .../qpid/server/registry/IApplicationRegistry.java | 68 -- .../security/auth/AuthenticationManager.java | 33 - .../auth/AuthenticationProviderInitialiser.java | 66 -- .../server/security/auth/AuthenticationResult.java | 43 - .../server/security/auth/CRAMMD5Initialiser.java | 38 - .../qpid/server/security/auth/JCAProvider.java | 46 -- .../security/auth/NullAuthenticationManager.java | 85 -- .../auth/PasswordFilePrincipalDatabase.java | 133 ---- .../server/security/auth/PrincipalDatabase.java | 45 -- .../security/auth/SASLAuthenticationManager.java | 227 ------ .../security/auth/UsernamePasswordInitialiser.java | 102 --- .../server/security/auth/UsernamePrincipal.java | 42 - .../auth/amqplain/AmqPlainInitialiser.java | 38 - .../security/auth/amqplain/AmqPlainSaslServer.java | 123 --- .../auth/amqplain/AmqPlainSaslServerFactory.java | 59 -- .../security/auth/plain/PlainInitialiser.java | 38 - .../security/auth/plain/PlainSaslServer.java | 144 ---- .../auth/plain/PlainSaslServerFactory.java | 59 -- .../src/org/apache/qpid/server/state/AMQState.java | 36 - .../apache/qpid/server/state/AMQStateManager.java | 222 ------ .../state/IllegalStateTransitionException.java | 48 -- .../server/state/StateAwareMethodListener.java | 40 - .../apache/qpid/server/state/StateListener.java | 30 - .../qpid/server/store/MemoryMessageStore.java | 145 ---- .../org/apache/qpid/server/store/MessageStore.java | 83 -- .../server/transport/ConnectorConfiguration.java | 86 -- .../qpid/server/transport/ThreadPoolFilter.java | 695 ----------------- .../src/org/apache/qpid/server/txn/TxnBuffer.java | 123 --- .../src/org/apache/qpid/server/txn/TxnOp.java | 54 -- .../apache/qpid/server/util/CircularBuffer.java | 126 --- .../server/util/ConcurrentLinkedQueueNoSize.java | 38 - .../org/apache/qpid/server/util/LoggingProxy.java | 105 --- .../qpid/server/util/NullApplicationRegistry.java | 109 --- .../java/org/apache/qpid/server/UnitTests.java | 39 + .../server/configuration/TestPropertyUtils.java | 53 ++ .../qpid/server/configuration/UnitTests.java | 35 + .../qpid/server/exchange/HeadersBindingTest.java | 203 +++++ .../org/apache/qpid/server/exchange/UnitTests.java | 35 + .../apache/qpid/server/util/LoggingProxyTest.java | 92 +++ .../org/apache/qpid/server/util/UnitTests.java | 35 + 267 files changed, 15639 insertions(+), 15147 deletions(-) create mode 100644 java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/ConsumerTagNotUniqueException.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/Main.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/ManagedChannel.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/RequiredDeliveryException.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/ack/TxAck.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessage.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMap.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/configuration/Configurator.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/exchange/DestNameExchange.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/exchange/DestWildExchange.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeFactory.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeInUseException.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeRegistry.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersBinding.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/exchange/Index.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/exchange/ManagedExchange.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/exchange/MessageRouter.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/exchange/NoRouteException.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/handler/BasicAckMethodHandler.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/handler/BasicCancelMethodHandler.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/handler/BasicPublishMethodHandler.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/handler/BasicQosHandler.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/handler/BasicRecoverMethodHandler.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/handler/ChannelCloseHandler.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/handler/ChannelCloseOkHandler.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/handler/ChannelFlowHandler.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/handler/ChannelOpenHandler.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionCloseMethodHandler.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionCloseOkMethodHandler.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionOpenMethodHandler.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionSecureOkMethodHandler.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionStartOkMethodHandler.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionTuneOkMethodHandler.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeclareHandler.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeleteHandler.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/handler/OnCurrentThreadExecutor.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/handler/QueueBindHandler.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeleteHandler.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/handler/TxCommitHandler.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/handler/TxRollbackHandler.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/handler/TxSelectHandler.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/jms/JmsConsumer.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/management/AMQManagedObject.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/management/DefaultManagedObject.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/management/MBeanAttribute.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/management/MBeanConstructor.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/management/MBeanDescription.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/management/MBeanIntrospector.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/management/MBeanOperation.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/management/MBeanOperationParameter.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/management/Managable.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/management/ManagedBroker.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/management/ManagedObject.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/management/ManagedObjectRegistry.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/management/ManagementConfiguration.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/management/NoopManagedObjectRegistry.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMethodEvent.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMethodListener.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPFastProtocolHandler.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPProtocolProvider.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/protocol/ExchangeInitialiser.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/protocol/HeartbeatConfig.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/protocol/ManagedConnection.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/queue/AsyncDeliveryConfig.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentDeliveryManager.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/queue/DefaultQueueRegistry.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/queue/DeliveryManager.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBindings.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/queue/FailedDequeueException.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/queue/ManagedQueue.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/queue/MessageCleanupException.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/queue/NoConsumersException.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/queue/QueueRegistry.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/queue/Subscription.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionFactory.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionManager.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionSet.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/queue/SynchronizedDeliveryManager.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/queue/WeightedSubscriptionManager.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/security/auth/AuthenticationManager.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/security/auth/AuthenticationProviderInitialiser.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/security/auth/AuthenticationResult.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/security/auth/CRAMMD5Initialiser.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/security/auth/JCAProvider.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/security/auth/NullAuthenticationManager.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/security/auth/PasswordFilePrincipalDatabase.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/security/auth/PrincipalDatabase.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/security/auth/SASLAuthenticationManager.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/security/auth/UsernamePasswordInitialiser.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/security/auth/UsernamePrincipal.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/security/auth/amqplain/AmqPlainInitialiser.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/security/auth/amqplain/AmqPlainSaslServer.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/security/auth/amqplain/AmqPlainSaslServerFactory.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/security/auth/plain/PlainInitialiser.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/security/auth/plain/PlainSaslServer.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/security/auth/plain/PlainSaslServerFactory.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/state/AMQState.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/state/AMQStateManager.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/state/IllegalStateTransitionException.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/state/StateAwareMethodListener.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/state/StateListener.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/store/MessageStore.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/transport/ConnectorConfiguration.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/transport/ThreadPoolFilter.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/txn/TxnBuffer.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/txn/TxnOp.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/util/CircularBuffer.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/util/ConcurrentLinkedQueueNoSize.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/util/LoggingProxy.java create mode 100644 java/broker/src/main/java/org/apache/qpid/server/util/NullApplicationRegistry.java delete mode 100644 java/broker/src/org/apache/qpid/server/AMQChannel.java delete mode 100644 java/broker/src/org/apache/qpid/server/ConsumerTagNotUniqueException.java delete mode 100644 java/broker/src/org/apache/qpid/server/Main.java delete mode 100644 java/broker/src/org/apache/qpid/server/ManagedChannel.java delete mode 100644 java/broker/src/org/apache/qpid/server/RequiredDeliveryException.java delete mode 100644 java/broker/src/org/apache/qpid/server/ack/TxAck.java delete mode 100644 java/broker/src/org/apache/qpid/server/ack/UnacknowledgedMessage.java delete mode 100644 java/broker/src/org/apache/qpid/server/ack/UnacknowledgedMessageMap.java delete mode 100644 java/broker/src/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java delete mode 100644 java/broker/src/org/apache/qpid/server/configuration/Configurator.java delete mode 100644 java/broker/src/org/apache/qpid/server/configuration/VirtualHostConfiguration.java delete mode 100644 java/broker/src/org/apache/qpid/server/exchange/AbstractExchange.java delete mode 100644 java/broker/src/org/apache/qpid/server/exchange/DefaultExchangeFactory.java delete mode 100644 java/broker/src/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java delete mode 100644 java/broker/src/org/apache/qpid/server/exchange/DestNameExchange.java delete mode 100644 java/broker/src/org/apache/qpid/server/exchange/DestWildExchange.java delete mode 100644 java/broker/src/org/apache/qpid/server/exchange/Exchange.java delete mode 100644 java/broker/src/org/apache/qpid/server/exchange/ExchangeFactory.java delete mode 100644 java/broker/src/org/apache/qpid/server/exchange/ExchangeInUseException.java delete mode 100644 java/broker/src/org/apache/qpid/server/exchange/ExchangeRegistry.java delete mode 100644 java/broker/src/org/apache/qpid/server/exchange/HeadersBinding.java delete mode 100644 java/broker/src/org/apache/qpid/server/exchange/HeadersExchange.java delete mode 100644 java/broker/src/org/apache/qpid/server/exchange/Index.java delete mode 100644 java/broker/src/org/apache/qpid/server/exchange/ManagedExchange.java delete mode 100644 java/broker/src/org/apache/qpid/server/exchange/MessageRouter.java delete mode 100644 java/broker/src/org/apache/qpid/server/exchange/NoRouteException.java delete mode 100644 java/broker/src/org/apache/qpid/server/handler/BasicAckMethodHandler.java delete mode 100644 java/broker/src/org/apache/qpid/server/handler/BasicCancelMethodHandler.java delete mode 100644 java/broker/src/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java delete mode 100644 java/broker/src/org/apache/qpid/server/handler/BasicPublishMethodHandler.java delete mode 100644 java/broker/src/org/apache/qpid/server/handler/BasicQosHandler.java delete mode 100644 java/broker/src/org/apache/qpid/server/handler/BasicRecoverMethodHandler.java delete mode 100644 java/broker/src/org/apache/qpid/server/handler/ChannelCloseHandler.java delete mode 100644 java/broker/src/org/apache/qpid/server/handler/ChannelCloseOkHandler.java delete mode 100644 java/broker/src/org/apache/qpid/server/handler/ChannelFlowHandler.java delete mode 100644 java/broker/src/org/apache/qpid/server/handler/ChannelOpenHandler.java delete mode 100644 java/broker/src/org/apache/qpid/server/handler/ConnectionCloseMethodHandler.java delete mode 100644 java/broker/src/org/apache/qpid/server/handler/ConnectionCloseOkMethodHandler.java delete mode 100644 java/broker/src/org/apache/qpid/server/handler/ConnectionOpenMethodHandler.java delete mode 100644 java/broker/src/org/apache/qpid/server/handler/ConnectionSecureOkMethodHandler.java delete mode 100644 java/broker/src/org/apache/qpid/server/handler/ConnectionStartOkMethodHandler.java delete mode 100644 java/broker/src/org/apache/qpid/server/handler/ConnectionTuneOkMethodHandler.java delete mode 100644 java/broker/src/org/apache/qpid/server/handler/ExchangeDeclareHandler.java delete mode 100644 java/broker/src/org/apache/qpid/server/handler/ExchangeDeleteHandler.java delete mode 100644 java/broker/src/org/apache/qpid/server/handler/OnCurrentThreadExecutor.java delete mode 100644 java/broker/src/org/apache/qpid/server/handler/QueueBindHandler.java delete mode 100644 java/broker/src/org/apache/qpid/server/handler/QueueDeclareHandler.java delete mode 100644 java/broker/src/org/apache/qpid/server/handler/QueueDeleteHandler.java delete mode 100644 java/broker/src/org/apache/qpid/server/handler/TxCommitHandler.java delete mode 100644 java/broker/src/org/apache/qpid/server/handler/TxRollbackHandler.java delete mode 100644 java/broker/src/org/apache/qpid/server/handler/TxSelectHandler.java delete mode 100644 java/broker/src/org/apache/qpid/server/jms/JmsConsumer.java delete mode 100644 java/broker/src/org/apache/qpid/server/management/AMQManagedObject.java delete mode 100644 java/broker/src/org/apache/qpid/server/management/DefaultManagedObject.java delete mode 100644 java/broker/src/org/apache/qpid/server/management/JMXManagedObjectRegistry.java delete mode 100644 java/broker/src/org/apache/qpid/server/management/MBeanAttribute.java delete mode 100644 java/broker/src/org/apache/qpid/server/management/MBeanConstructor.java delete mode 100644 java/broker/src/org/apache/qpid/server/management/MBeanDescription.java delete mode 100644 java/broker/src/org/apache/qpid/server/management/MBeanIntrospector.java delete mode 100644 java/broker/src/org/apache/qpid/server/management/MBeanOperation.java delete mode 100644 java/broker/src/org/apache/qpid/server/management/MBeanOperationParameter.java delete mode 100644 java/broker/src/org/apache/qpid/server/management/Managable.java delete mode 100644 java/broker/src/org/apache/qpid/server/management/ManagedBroker.java delete mode 100644 java/broker/src/org/apache/qpid/server/management/ManagedObject.java delete mode 100644 java/broker/src/org/apache/qpid/server/management/ManagedObjectRegistry.java delete mode 100644 java/broker/src/org/apache/qpid/server/management/ManagementConfiguration.java delete mode 100644 java/broker/src/org/apache/qpid/server/management/NoopManagedObjectRegistry.java delete mode 100644 java/broker/src/org/apache/qpid/server/protocol/AMQMethodEvent.java delete mode 100644 java/broker/src/org/apache/qpid/server/protocol/AMQMethodListener.java delete mode 100644 java/broker/src/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java delete mode 100644 java/broker/src/org/apache/qpid/server/protocol/AMQPFastProtocolHandler.java delete mode 100644 java/broker/src/org/apache/qpid/server/protocol/AMQPProtocolProvider.java delete mode 100644 java/broker/src/org/apache/qpid/server/protocol/AMQProtocolSession.java delete mode 100644 java/broker/src/org/apache/qpid/server/protocol/ExchangeInitialiser.java delete mode 100644 java/broker/src/org/apache/qpid/server/protocol/HeartbeatConfig.java delete mode 100644 java/broker/src/org/apache/qpid/server/protocol/ManagedConnection.java delete mode 100644 java/broker/src/org/apache/qpid/server/queue/AMQMessage.java delete mode 100644 java/broker/src/org/apache/qpid/server/queue/AMQQueue.java delete mode 100644 java/broker/src/org/apache/qpid/server/queue/AsyncDeliveryConfig.java delete mode 100644 java/broker/src/org/apache/qpid/server/queue/ConcurrentDeliveryManager.java delete mode 100644 java/broker/src/org/apache/qpid/server/queue/DefaultQueueRegistry.java delete mode 100644 java/broker/src/org/apache/qpid/server/queue/DeliveryManager.java delete mode 100644 java/broker/src/org/apache/qpid/server/queue/ExchangeBindings.java delete mode 100644 java/broker/src/org/apache/qpid/server/queue/FailedDequeueException.java delete mode 100644 java/broker/src/org/apache/qpid/server/queue/ManagedQueue.java delete mode 100644 java/broker/src/org/apache/qpid/server/queue/MessageCleanupException.java delete mode 100644 java/broker/src/org/apache/qpid/server/queue/NoConsumersException.java delete mode 100644 java/broker/src/org/apache/qpid/server/queue/QueueRegistry.java delete mode 100644 java/broker/src/org/apache/qpid/server/queue/Subscription.java delete mode 100644 java/broker/src/org/apache/qpid/server/queue/SubscriptionFactory.java delete mode 100644 java/broker/src/org/apache/qpid/server/queue/SubscriptionImpl.java delete mode 100644 java/broker/src/org/apache/qpid/server/queue/SubscriptionManager.java delete mode 100644 java/broker/src/org/apache/qpid/server/queue/SubscriptionSet.java delete mode 100644 java/broker/src/org/apache/qpid/server/queue/SynchronizedDeliveryManager.java delete mode 100644 java/broker/src/org/apache/qpid/server/queue/WeightedSubscriptionManager.java delete mode 100644 java/broker/src/org/apache/qpid/server/registry/ApplicationRegistry.java delete mode 100644 java/broker/src/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java delete mode 100644 java/broker/src/org/apache/qpid/server/registry/IApplicationRegistry.java delete mode 100644 java/broker/src/org/apache/qpid/server/security/auth/AuthenticationManager.java delete mode 100644 java/broker/src/org/apache/qpid/server/security/auth/AuthenticationProviderInitialiser.java delete mode 100644 java/broker/src/org/apache/qpid/server/security/auth/AuthenticationResult.java delete mode 100644 java/broker/src/org/apache/qpid/server/security/auth/CRAMMD5Initialiser.java delete mode 100644 java/broker/src/org/apache/qpid/server/security/auth/JCAProvider.java delete mode 100644 java/broker/src/org/apache/qpid/server/security/auth/NullAuthenticationManager.java delete mode 100644 java/broker/src/org/apache/qpid/server/security/auth/PasswordFilePrincipalDatabase.java delete mode 100644 java/broker/src/org/apache/qpid/server/security/auth/PrincipalDatabase.java delete mode 100644 java/broker/src/org/apache/qpid/server/security/auth/SASLAuthenticationManager.java delete mode 100644 java/broker/src/org/apache/qpid/server/security/auth/UsernamePasswordInitialiser.java delete mode 100644 java/broker/src/org/apache/qpid/server/security/auth/UsernamePrincipal.java delete mode 100644 java/broker/src/org/apache/qpid/server/security/auth/amqplain/AmqPlainInitialiser.java delete mode 100644 java/broker/src/org/apache/qpid/server/security/auth/amqplain/AmqPlainSaslServer.java delete mode 100644 java/broker/src/org/apache/qpid/server/security/auth/amqplain/AmqPlainSaslServerFactory.java delete mode 100644 java/broker/src/org/apache/qpid/server/security/auth/plain/PlainInitialiser.java delete mode 100644 java/broker/src/org/apache/qpid/server/security/auth/plain/PlainSaslServer.java delete mode 100644 java/broker/src/org/apache/qpid/server/security/auth/plain/PlainSaslServerFactory.java delete mode 100644 java/broker/src/org/apache/qpid/server/state/AMQState.java delete mode 100644 java/broker/src/org/apache/qpid/server/state/AMQStateManager.java delete mode 100644 java/broker/src/org/apache/qpid/server/state/IllegalStateTransitionException.java delete mode 100644 java/broker/src/org/apache/qpid/server/state/StateAwareMethodListener.java delete mode 100644 java/broker/src/org/apache/qpid/server/state/StateListener.java delete mode 100644 java/broker/src/org/apache/qpid/server/store/MemoryMessageStore.java delete mode 100644 java/broker/src/org/apache/qpid/server/store/MessageStore.java delete mode 100644 java/broker/src/org/apache/qpid/server/transport/ConnectorConfiguration.java delete mode 100644 java/broker/src/org/apache/qpid/server/transport/ThreadPoolFilter.java delete mode 100644 java/broker/src/org/apache/qpid/server/txn/TxnBuffer.java delete mode 100644 java/broker/src/org/apache/qpid/server/txn/TxnOp.java delete mode 100644 java/broker/src/org/apache/qpid/server/util/CircularBuffer.java delete mode 100644 java/broker/src/org/apache/qpid/server/util/ConcurrentLinkedQueueNoSize.java delete mode 100644 java/broker/src/org/apache/qpid/server/util/LoggingProxy.java delete mode 100644 java/broker/src/org/apache/qpid/server/util/NullApplicationRegistry.java create mode 100644 java/broker/src/test/java/org/apache/qpid/server/UnitTests.java create mode 100644 java/broker/src/test/java/org/apache/qpid/server/configuration/TestPropertyUtils.java create mode 100644 java/broker/src/test/java/org/apache/qpid/server/configuration/UnitTests.java create mode 100644 java/broker/src/test/java/org/apache/qpid/server/exchange/HeadersBindingTest.java create mode 100644 java/broker/src/test/java/org/apache/qpid/server/exchange/UnitTests.java create mode 100644 java/broker/src/test/java/org/apache/qpid/server/util/LoggingProxyTest.java create mode 100644 java/broker/src/test/java/org/apache/qpid/server/util/UnitTests.java (limited to 'java/broker/src') diff --git a/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java b/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java new file mode 100644 index 0000000000..a6cb4523cf --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java @@ -0,0 +1,788 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server; + +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQDataBlock; +import org.apache.qpid.framing.BasicPublishBody; +import org.apache.qpid.framing.ContentBody; +import org.apache.qpid.framing.ContentHeaderBody; +import org.apache.qpid.server.ack.TxAck; +import org.apache.qpid.server.ack.UnacknowledgedMessage; +import org.apache.qpid.server.ack.UnacknowledgedMessageMap; +import org.apache.qpid.server.ack.UnacknowledgedMessageMapImpl; +import org.apache.qpid.server.exchange.MessageRouter; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.queue.NoConsumersException; +import org.apache.qpid.server.store.MessageStore; +import org.apache.qpid.server.txn.TxnBuffer; +import org.apache.qpid.server.txn.TxnOp; + +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicLong; + +public class AMQChannel +{ + public static final int DEFAULT_PREFETCH = 5000; + + private static final Logger _log = Logger.getLogger(AMQChannel.class); + + private final int _channelId; + + private boolean _transactional; + + private long _prefetch_HighWaterMark; + + private long _prefetch_LowWaterMark; + + /** + * The delivery tag is unique per channel. This is pre-incremented before putting into the deliver frame so that + * value of this represents the last tag sent out + */ + private AtomicLong _deliveryTag = new AtomicLong(0); + + /** + * A channel has a default queue (the last declared) that is used when no queue name is + * explictily set + */ + private AMQQueue _defaultQueue; + + /** + * This tag is unique per subscription to a queue. The server returns this in response to a + * basic.consume request. + */ + private int _consumerTag; + + /** + * The current message - which may be partial in the sense that not all frames have been received yet - + * which has been received by this channel. As the frames are received the message gets updated and once all + * frames have been received the message can then be routed. + */ + private AMQMessage _currentMessage; + + /** + * Maps from consumer tag to queue instance. Allows us to unsubscribe from a queue. + */ + private final Map _consumerTag2QueueMap = new TreeMap(); + + private final MessageStore _messageStore; + + private final Object _unacknowledgedMessageMapLock = new Object(); + + private Map _unacknowledgedMessageMap = new LinkedHashMap(DEFAULT_PREFETCH); + + private long _lastDeliveryTag; + + private final AtomicBoolean _suspended = new AtomicBoolean(false); + + private final MessageRouter _exchanges; + + private final TxnBuffer _txnBuffer; + + private TxAck ackOp; + + private final List _returns = new LinkedList(); + + public AMQChannel(int channelId, MessageStore messageStore, MessageRouter exchanges) + throws AMQException + { + _channelId = channelId; + _prefetch_HighWaterMark = DEFAULT_PREFETCH; + _prefetch_LowWaterMark = _prefetch_HighWaterMark / 2; + _messageStore = messageStore; + _exchanges = exchanges; + _txnBuffer = new TxnBuffer(_messageStore); + } + + public int getChannelId() + { + return _channelId; + } + + public boolean isTransactional() + { + return _transactional; + } + + public void setTransactional(boolean transactional) + { + _transactional = transactional; + } + + public long getPrefetchCount() + { + return _prefetch_HighWaterMark; + } + + public void setPrefetchCount(long prefetchCount) + { + _prefetch_HighWaterMark = prefetchCount; + } + + public long getPrefetchLowMarkCount() + { + return _prefetch_LowWaterMark; + } + + public void setPrefetchLowMarkCount(long prefetchCount) + { + _prefetch_LowWaterMark = prefetchCount; + } + + public long getPrefetchHighMarkCount() + { + return _prefetch_HighWaterMark; + } + + public void setPrefetchHighMarkCount(long prefetchCount) + { + _prefetch_HighWaterMark = prefetchCount; + } + + + public void setPublishFrame(BasicPublishBody publishBody, AMQProtocolSession publisher) throws AMQException + { + _currentMessage = new AMQMessage(_messageStore, publishBody); + _currentMessage.setPublisher(publisher); + } + + public void publishContentHeader(ContentHeaderBody contentHeaderBody) + throws AMQException + { + if (_currentMessage == null) + { + throw new AMQException("Received content header without previously receiving a BasicDeliver frame"); + } + else + { + _currentMessage.setContentHeaderBody(contentHeaderBody); + // check and route if header says body length is zero + if (contentHeaderBody.bodySize == 0) + { + routeCurrentMessage(); + } + } + } + + public void publishContentBody(ContentBody contentBody) + throws AMQException + { + if (_currentMessage == null) + { + throw new AMQException("Received content body without previously receiving a JmsPublishBody"); + } + if (_currentMessage.getContentHeaderBody() == null) + { + throw new AMQException("Received content body without previously receiving a content header"); + } + + _currentMessage.addContentBodyFrame(contentBody); + if (_currentMessage.isAllContentReceived()) + { + routeCurrentMessage(); + } + } + + protected void routeCurrentMessage() throws AMQException + { + if (_transactional) + { + //don't create a transaction unless needed + if (_currentMessage.isPersistent()) + { + _txnBuffer.containsPersistentChanges(); + } + + //A publication will result in the enlisting of several + //TxnOps. The first is an op that will store the message. + //Following that (and ordering is important), an op will + //be added for every queue onto which the message is + //enqueued. Finally a cleanup op will be added to decrement + //the reference associated with the routing. + Store storeOp = new Store(_currentMessage); + _txnBuffer.enlist(storeOp); + _currentMessage.setTxnBuffer(_txnBuffer); + try + { + _exchanges.routeContent(_currentMessage); + _txnBuffer.enlist(new Cleanup(_currentMessage)); + } + catch (RequiredDeliveryException e) + { + //Can only be due to the mandatory flag, as no attempt + //has yet been made to deliver the message. The + //message will thus not have been delivered to any + //queue so we can return the message (without killing + //the transaction) and for efficiency remove the store + //operation from the buffer. + _txnBuffer.cancel(storeOp); + throw e; + } + finally + { + _currentMessage = null; + } + } + else + { + try + { + _exchanges.routeContent(_currentMessage); + //following check implements the functionality + //required by the 'immediate' flag: + _currentMessage.checkDeliveredToConsumer(); + } + finally + { + _currentMessage.decrementReference(); + _currentMessage = null; + } + } + } + + public long getNextDeliveryTag() + { + return _deliveryTag.incrementAndGet(); + } + + public int getNextConsumerTag() + { + return ++_consumerTag; + } + + /** + * Subscribe to a queue. We register all subscriptions in the channel so that + * if the channel is closed we can clean up all subscriptions, even if the + * client does not explicitly unsubscribe from all queues. + * + * @param tag the tag chosen by the client (if null, server will generate one) + * @param queue the queue to subscribe to + * @param session the protocol session of the subscriber + * @return the consumer tag. This is returned to the subscriber and used in + * subsequent unsubscribe requests + * @throws ConsumerTagNotUniqueException if the tag is not unique + * @throws AMQException if something goes wrong + */ + public String subscribeToQueue(String tag, AMQQueue queue, AMQProtocolSession session, boolean acks) throws AMQException, ConsumerTagNotUniqueException + { + if (tag == null) + { + tag = "sgen_" + getNextConsumerTag(); + } + if (_consumerTag2QueueMap.containsKey(tag)) + { + throw new ConsumerTagNotUniqueException(); + } + + queue.registerProtocolSession(session, _channelId, tag, acks); + _consumerTag2QueueMap.put(tag, queue); + return tag; + } + + + public void unsubscribeConsumer(AMQProtocolSession session, String consumerTag) throws AMQException + { + AMQQueue q = _consumerTag2QueueMap.remove(consumerTag); + if (q != null) + { + q.unregisterProtocolSession(session, _channelId, consumerTag); + } + } + + /** + * Called from the protocol session to close this channel and clean up. + * + * @throws AMQException if there is an error during closure + */ + public void close(AMQProtocolSession session) throws AMQException + { + if (_transactional) + { + synchronized(_txnBuffer) + { + _txnBuffer.rollback();//releases messages + } + } + unsubscribeAllConsumers(session); + requeue(); + } + + private void unsubscribeAllConsumers(AMQProtocolSession session) throws AMQException + { + _log.info("Unsubscribing all consumers on channel " + toString()); + for (Map.Entry me : _consumerTag2QueueMap.entrySet()) + { + me.getValue().unregisterProtocolSession(session, _channelId, me.getKey()); + } + _consumerTag2QueueMap.clear(); + } + + /** + * Add a message to the channel-based list of unacknowledged messages + * + * @param message + * @param deliveryTag + * @param queue + */ + public void addUnacknowledgedMessage(AMQMessage message, long deliveryTag, String consumerTag, AMQQueue queue) + { + synchronized(_unacknowledgedMessageMapLock) + { + _unacknowledgedMessageMap.put(deliveryTag, new UnacknowledgedMessage(queue, message, consumerTag, deliveryTag)); + _lastDeliveryTag = deliveryTag; + checkSuspension(); + } + } + + /** + * Called to attempt re-enqueue all outstanding unacknowledged messages on the channel. + * May result in delivery to this same channel or to other subscribers. + */ + public void requeue() throws AMQException + { + // we must create a new map since all the messages will get a new delivery tag when they are redelivered + Map currentList; + synchronized(_unacknowledgedMessageMapLock) + { + currentList = _unacknowledgedMessageMap; + _unacknowledgedMessageMap = new LinkedHashMap(DEFAULT_PREFETCH); + } + + for (UnacknowledgedMessage unacked : currentList.values()) + { + if (unacked.queue != null) + { + unacked.queue.deliver(unacked.message); + } + } + } + + /** + * Called to resend all outstanding unacknowledged messages to this same channel. + */ + public void resend(AMQProtocolSession session) + { + //messages go to this channel + synchronized(_unacknowledgedMessageMapLock) + { + for (Map.Entry entry : _unacknowledgedMessageMap.entrySet()) + { + long deliveryTag = entry.getKey(); + String consumerTag = entry.getValue().consumerTag; + AMQMessage msg = entry.getValue().message; + + session.writeFrame(msg.getDataBlock(_channelId, consumerTag, deliveryTag)); + } + } + } + + /** + * Callback indicating that a queue has been deleted. We must update the structure of unacknowledged + * messages to remove the queue reference and also decrement any message reference counts, without + * actually removing the item sine we may get an ack for a delivery tag that was generated from the + * deleted queue. + * + * @param queue + */ + public void queueDeleted(AMQQueue queue) + { + synchronized(_unacknowledgedMessageMapLock) + { + for (Map.Entry unacked : _unacknowledgedMessageMap.entrySet()) + { + final UnacknowledgedMessage unackedMsg = unacked.getValue(); + // we can compare the reference safely in this case + if (unackedMsg.queue == queue) + { + unackedMsg.queue = null; + try + { + unackedMsg.message.decrementReference(); + } + catch (AMQException e) + { + _log.error("Error decrementing ref count on message " + unackedMsg.message.getMessageId() + ": " + + e, e); + } + } + } + } + } + + /** + * Acknowledge one or more messages. + * + * @param deliveryTag the last delivery tag + * @param multiple if true will acknowledge all messages up to an including the delivery tag. if false only + * acknowledges the single message specified by the delivery tag + * @throws AMQException if the delivery tag is unknown (e.g. not outstanding) on this channel + */ + public void acknowledgeMessage(long deliveryTag, boolean multiple) throws AMQException + { + if (_transactional) + { + //check that the tag exists to give early failure + if (!multiple || deliveryTag > 0) + { + checkAck(deliveryTag); + } + //we use a single txn op for all acks and update this op + //as new acks come in. If this is the first ack in the txn + //we will need to create and enlist the op. + if (ackOp == null) + { + ackOp = new TxAck(new AckMap()); + _txnBuffer.enlist(ackOp); + } + //update the op to include this ack request + if (multiple && deliveryTag == 0) + { + synchronized(_unacknowledgedMessageMapLock) + { + //if have signalled to ack all, that refers only + //to all at this time + ackOp.update(_lastDeliveryTag, multiple); + } + } + else + { + ackOp.update(deliveryTag, multiple); + } + } + else + { + handleAcknowledgement(deliveryTag, multiple); + } + } + + private void checkAck(long deliveryTag) throws AMQException + { + synchronized(_unacknowledgedMessageMapLock) + { + if (!_unacknowledgedMessageMap.containsKey(deliveryTag)) + { + throw new AMQException("Ack with delivery tag " + deliveryTag + " not known for channel"); + } + } + } + + private void handleAcknowledgement(long deliveryTag, boolean multiple) throws AMQException + { + if (multiple) + { + LinkedList acked = new LinkedList(); + synchronized(_unacknowledgedMessageMapLock) + { + if (deliveryTag == 0) + { + //Spec 2.1.6.11 ... If the multiple field is 1, and the delivery tag is zero, tells the server to acknowledge all outstanding mesages. + _log.trace("Multiple ack on delivery tag 0. ACKing all messages. Current count:" + _unacknowledgedMessageMap.size()); + acked = new LinkedList(_unacknowledgedMessageMap.values()); + _unacknowledgedMessageMap.clear(); + } + else + { + if (!_unacknowledgedMessageMap.containsKey(deliveryTag)) + { + throw new AMQException("Multiple ack on delivery tag " + deliveryTag + " not known for channel"); + } + Iterator> i = _unacknowledgedMessageMap.entrySet().iterator(); + + while (i.hasNext()) + { + + Map.Entry unacked = i.next(); + + if (unacked.getKey() > deliveryTag) + { + //This should not occur now. + throw new AMQException("UnacknowledgedMessageMap is out of order:" + unacked.getKey() + " When deliveryTag is:" + deliveryTag + "ES:" + _unacknowledgedMessageMap.entrySet().toString()); + } + + i.remove(); + + acked.add(unacked.getValue()); + if (unacked.getKey() == deliveryTag) + { + break; + } + } + } + }// synchronized + + if (_log.isTraceEnabled()) + { + _log.trace("Received multiple ack for delivery tag " + deliveryTag + ". Removing " + + acked.size() + " items."); + } + + for (UnacknowledgedMessage msg : acked) + { + msg.discard(); + } + + } + else + { + UnacknowledgedMessage msg; + synchronized(_unacknowledgedMessageMapLock) + { + msg = _unacknowledgedMessageMap.remove(deliveryTag); + } + + if (msg == null) + { + _log.trace("Single ack on delivery tag " + deliveryTag + " not known for channel:" + _channelId); + throw new AMQException("Single ack on delivery tag " + deliveryTag + " not known for channel:" + _channelId); + } + msg.discard(); + if (_log.isTraceEnabled()) + { + _log.trace("Received non-multiple ack for messaging with delivery tag " + deliveryTag); + } + } + + checkSuspension(); + } + + /** + * Used only for testing purposes. + * + * @return the map of unacknowledged messages + */ + public Map getUnacknowledgedMessageMap() + { + return _unacknowledgedMessageMap; + } + + private void checkSuspension() + { + boolean suspend; + //noinspection SynchronizeOnNonFinalField + synchronized(_unacknowledgedMessageMapLock) + { + suspend = _unacknowledgedMessageMap.size() >= _prefetch_HighWaterMark; + } + setSuspended(suspend); + } + + public void setSuspended(boolean suspended) + { + boolean isSuspended = _suspended.get(); + + if (isSuspended && !suspended) + { + synchronized(_unacknowledgedMessageMapLock) + { + // Continue being suspended if we are above the _prefetch_LowWaterMark + suspended = _unacknowledgedMessageMap.size() > _prefetch_LowWaterMark; + } + } + + boolean wasSuspended = _suspended.getAndSet(suspended); + if (wasSuspended != suspended) + { + if (wasSuspended) + { + _log.debug("Unsuspending channel " + this); + //may need to deliver queued messages + for (AMQQueue q : _consumerTag2QueueMap.values()) + { + q.deliverAsync(); + } + } + else + { + _log.debug("Suspending channel " + this); + } + } + } + + public boolean isSuspended() + { + return _suspended.get(); + } + + public void commit() throws AMQException + { + if (ackOp != null) + { + ackOp.consolidate(); + if (ackOp.checkPersistent()) + { + _txnBuffer.containsPersistentChanges(); + } + ackOp = null;//already enlisted, after commit will reset regardless of outcome + } + + _txnBuffer.commit(); + //TODO: may need to return 'immediate' messages at this point + } + + public void rollback() throws AMQException + { + //need to protect rollback and close from each other... + synchronized(_txnBuffer) + { + _txnBuffer.rollback(); + } + } + + public String toString() + { + StringBuilder sb = new StringBuilder(30); + sb.append("Channel: id ").append(_channelId).append(", transaction mode: ").append(_transactional); + sb.append(", prefetch marks: ").append(_prefetch_LowWaterMark); + sb.append("/").append(_prefetch_HighWaterMark); + return sb.toString(); + } + + public void setDefaultQueue(AMQQueue queue) + { + _defaultQueue = queue; + } + + public AMQQueue getDefaultQueue() + { + return _defaultQueue; + } + + public void processReturns(AMQProtocolSession session) + { + for (AMQDataBlock block : _returns) + { + session.writeFrame(block); + } + _returns.clear(); + } + + //we use this wrapper to ensure we are always using the correct + //map instance (its not final unfortunately) + private class AckMap implements UnacknowledgedMessageMap + { + public void collect(long deliveryTag, boolean multiple, List msgs) + { + impl().collect(deliveryTag, multiple, msgs); + } + + public void remove(List msgs) + { + impl().remove(msgs); + } + + private UnacknowledgedMessageMap impl() + { + return new UnacknowledgedMessageMapImpl(_unacknowledgedMessageMapLock, _unacknowledgedMessageMap); + } + } + + private class Store implements TxnOp + { + //just use this to do a store of the message during the + //prepare phase. Any enqueueing etc is done by TxnOps enlisted + //by the queues themselves. + private final AMQMessage _msg; + + Store(AMQMessage msg) + { + _msg = msg; + } + + public void prepare() throws AMQException + { + _msg.storeMessage(); + //the routers reference can now be released + _msg.decrementReference(); + } + + public void undoPrepare() + { + } + + public void commit() + { + } + + public void rollback() + { + } + } + + private class Cleanup implements TxnOp + { + private final AMQMessage _msg; + + Cleanup(AMQMessage msg) + { + _msg = msg; + } + + public void prepare() throws AMQException + { + } + + public void undoPrepare() + { + //don't need to do anything here, if the store's txn failed + //when processing prepare then the message was not stored + //or enqueued on any queues and can be discarded + } + + public void commit() + { + //The routers reference can now be released. This is done + //here to ensure that it happens after the queues that + //enqueue it have incremented their counts (which as a + //memory only operation is done in the commit phase). + try + { + _msg.decrementReference(); + } + catch (AMQException e) + { + _log.error("On commiting transaction, failed to cleanup unused message: " + e, e); + } + try + { + _msg.checkDeliveredToConsumer(); + } + catch (NoConsumersException e) + { + //TODO: store this for delivery after the commit-ok + _returns.add(e.getReturnMessage(_channelId)); + } + } + + public void rollback() + { + } + } + +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/ConsumerTagNotUniqueException.java b/java/broker/src/main/java/org/apache/qpid/server/ConsumerTagNotUniqueException.java new file mode 100644 index 0000000000..9a98af5689 --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/ConsumerTagNotUniqueException.java @@ -0,0 +1,25 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server; + +public class ConsumerTagNotUniqueException extends Exception +{ +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/Main.java b/java/broker/src/main/java/org/apache/qpid/server/Main.java new file mode 100644 index 0000000000..d2dacb6140 --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/Main.java @@ -0,0 +1,627 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server; + +import org.apache.qpid.framing.ProtocolVersionList; +import org.apache.qpid.pool.ReadWriteThreadModel; +import org.apache.qpid.server.protocol.AMQPFastProtocolHandler; +import org.apache.qpid.server.protocol.AMQPProtocolProvider; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.registry.ConfigurationFileApplicationRegistry; +import org.apache.qpid.server.registry.IApplicationRegistry; +import org.apache.qpid.server.transport.ConnectorConfiguration; +import org.apache.qpid.server.configuration.VirtualHostConfiguration; +import org.apache.qpid.server.management.*; +import org.apache.qpid.server.queue.QueueRegistry; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.exchange.ExchangeRegistry; +import org.apache.qpid.server.exchange.ExchangeFactory; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.store.MessageStore; +import org.apache.qpid.AMQException; +import org.apache.qpid.url.URLSyntaxException; +import org.apache.commons.cli.*; +import org.apache.commons.configuration.ConfigurationException; +import org.apache.log4j.BasicConfigurator; +import org.apache.log4j.Logger; +import org.apache.log4j.xml.DOMConfigurator; +import org.apache.mina.common.ByteBuffer; +import org.apache.mina.common.IoAcceptor; +import org.apache.mina.common.SimpleByteBufferAllocator; +import org.apache.mina.transport.socket.nio.SocketSessionConfig; + +import javax.management.JMException; +import javax.management.MBeanException; +import javax.management.NotCompliantMBeanException; +import javax.management.ObjectName; +import javax.management.MalformedObjectNameException; + +import java.io.File; +import java.io.IOException; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.util.StringTokenizer; +import java.util.Collection; +import java.util.List; + +/** + * Main entry point for AMQPD. + */ +public class Main implements ProtocolVersionList +{ + private static final Logger _logger = Logger.getLogger(Main.class); + + private static final String DEFAULT_CONFIG_FILE = "etc/config.xml"; + + private static final String DEFAULT_LOG_CONFIG_FILENAME = "log4j.xml"; + + protected static class InitException extends Exception + { + InitException(String msg) + { + super(msg); + } + } + + protected final Options options = new Options(); + protected CommandLine commandLine; + + protected Main(String[] args) + { + setOptions(options); + if (parseCommandline(args)) + { + execute(); + } + } + + protected boolean parseCommandline(String[] args) + { + try + { + commandLine = new PosixParser().parse(options, args); + return true; + } + catch (ParseException e) + { + System.err.println("Error: " + e.getMessage()); + HelpFormatter formatter = new HelpFormatter(); + formatter.printHelp("Qpid", options, true); + return false; + } + } + + protected void setOptions(Options options) + { + Option help = new Option("h", "help", false, "print this message"); + Option version = new Option("v", "version", false, "print the version information and exit"); + Option configFile = OptionBuilder.withArgName("file").hasArg().withDescription("use given configuration file"). + withLongOpt("config").create("c"); + Option port = OptionBuilder.withArgName("port").hasArg().withDescription("listen on the specified port. Overrides any value in the config file"). + withLongOpt("port").create("p"); + Option bind = OptionBuilder.withArgName("bind").hasArg().withDescription("bind to the specified address. Overrides any value in the config file"). + withLongOpt("bind").create("b"); + Option logconfig = OptionBuilder.withArgName("logconfig").hasArg().withDescription("use the specified log4j xml configuration file. By " + + "default looks for a file named " + DEFAULT_LOG_CONFIG_FILENAME + " in the same directory as the configuration file"). + withLongOpt("logconfig").create("l"); + Option logwatchconfig = OptionBuilder.withArgName("logwatch").hasArg().withDescription("monitor the log file configuration file for changes. Units are seconds. " + + "Zero means do not check for changes.").withLongOpt("logwatch").create("w"); + + options.addOption(help); + options.addOption(version); + options.addOption(configFile); + options.addOption(logconfig); + options.addOption(logwatchconfig); + options.addOption(port); + options.addOption(bind); + } + + protected void execute() + { + // note this understands either --help or -h. If an option only has a long name you can use that but if + // an option has a short name and a long name you must use the short name here. + if (commandLine.hasOption("h")) + { + HelpFormatter formatter = new HelpFormatter(); + formatter.printHelp("Qpid", options, true); + } + else if (commandLine.hasOption("v")) + { + String ver = "Qpid 0.9.0.0"; + String protocol = "AMQP version(s) [major.minor]: "; + for (int i = 0; i < pv.length; i++) + { + if (i > 0) + { + protocol += ", "; + } + protocol += pv[i][PROTOCOL_MAJOR] + "." + pv[i][PROTOCOL_MINOR]; + } + System.out.println(ver + " (" + protocol + ")"); + } + else + { + try + { + startup(); + } + catch (InitException e) + { + System.out.println(e.getMessage()); + } + catch (ConfigurationException e) + { + System.out.println("Error configuring message broker: " + e); + e.printStackTrace(); + } + catch (Exception e) + { + System.out.println("Error intialising message broker: " + e); + e.printStackTrace(); + } + } + } + + + protected void startup() throws InitException, ConfigurationException, Exception + { + final String QpidHome = System.getProperty("QPID_HOME"); + final File defaultConfigFile = new File(QpidHome, DEFAULT_CONFIG_FILE); + final File configFile = new File(commandLine.getOptionValue("c", defaultConfigFile.getPath())); + if (!configFile.exists()) + { + String error = "File " + configFile + " could not be found. Check the file exists and is readable."; + + if (QpidHome == null) + { + error = error + "\nNote: Qpid_HOME is not set."; + } + + throw new InitException(error); + } + else + { + System.out.println("Using configuration file " + configFile.getAbsolutePath()); + } + + String logConfig = commandLine.getOptionValue("l"); + String logWatchConfig = commandLine.getOptionValue("w", "0"); + if (logConfig != null) + { + File logConfigFile = new File(logConfig); + configureLogging(logConfigFile, logWatchConfig); + } + else + { + File configFileDirectory = configFile.getParentFile(); + File logConfigFile = new File(configFileDirectory, DEFAULT_LOG_CONFIG_FILENAME); + configureLogging(logConfigFile, logWatchConfig); + } + + ApplicationRegistry.initialise(new ConfigurationFileApplicationRegistry(configFile)); + + _logger.info("Starting Qpid.AMQP broker"); + + ConnectorConfiguration connectorConfig = ApplicationRegistry.getInstance(). + getConfiguredObject(ConnectorConfiguration.class); + + // From old Mina + //ByteBuffer.setUseDirectBuffers(connectorConfig.enableDirectBuffers); + + // the MINA default is currently to use the pooled allocator although this may change in future + // once more testing of the performance of the simple allocator has been done + if (!connectorConfig.enablePooledAllocator) + { + ByteBuffer.setAllocator(new SimpleByteBufferAllocator()); + } + + int port = connectorConfig.port; + + String portStr = commandLine.getOptionValue("p"); + if (portStr != null) + { + try + { + port = Integer.parseInt(portStr); + } + catch (NumberFormatException e) + { + throw new InitException("Invalid port: " + portStr); + } + } + + String VIRTUAL_HOSTS = "virtualhosts"; + + Object virtualHosts = ApplicationRegistry.getInstance().getConfiguration().getProperty(VIRTUAL_HOSTS); + + if (virtualHosts != null) + { + if (virtualHosts instanceof Collection) + { + int totalVHosts = ((Collection) virtualHosts).size(); + for (int vhost = 0; vhost < totalVHosts; vhost++) + { + setupVirtualHosts(configFile.getParent(), (String) ((List) virtualHosts).get(vhost)); + } + } + else + { + setupVirtualHosts(configFile.getParent(), (String) virtualHosts); + } + } + bind(port, connectorConfig); + + createAndRegisterBrokerMBean(); + } + + protected void setupVirtualHosts(String configFileParent, String configFilePath) throws ConfigurationException, AMQException, URLSyntaxException + { + String configVar = "${conf}"; + + if (configFilePath.startsWith(configVar)) + { + configFilePath = configFileParent + configFilePath.substring(configVar.length()); + } + + if (configFilePath.indexOf(".xml") != -1) + { + VirtualHostConfiguration vHostConfig = new VirtualHostConfiguration(configFilePath); + vHostConfig.performBindings(); + } + else + { + // the virtualhosts value is a path. Search it for XML files. + + File virtualHostDir = new File(configFilePath); + + String[] fileNames = virtualHostDir.list(); + + for (int each = 0; each < fileNames.length; each++) + { + if (fileNames[each].endsWith(".xml")) + { + VirtualHostConfiguration vHostConfig = new VirtualHostConfiguration(configFilePath + "/" + fileNames[each]); + vHostConfig.performBindings(); + } + } + } + } + + protected void bind(int port, ConnectorConfiguration connectorConfig) + { + String bindAddr = commandLine.getOptionValue("b"); + if (bindAddr == null) + { + bindAddr = connectorConfig.bindAddress; + } + + try + { + //IoAcceptor acceptor = new SocketAcceptor(connectorConfig.processors); + IoAcceptor acceptor = connectorConfig.createAcceptor(); + + SocketSessionConfig sc; + + sc = (SocketSessionConfig) acceptor.getSessionConfig(); + + sc.setReceiveBufferSize(connectorConfig.socketReceiveBufferSize); + sc.setSendBufferSize(connectorConfig.socketWriteBuferSize); + sc.setTcpNoDelay(connectorConfig.tcpNoDelay); + + // if we do not use the executor pool threading model we get the default leader follower + // implementation provided by MINA + if (connectorConfig.enableExecutorPool) + { + acceptor.setThreadModel(new ReadWriteThreadModel()); + } + + if (connectorConfig.enableNonSSL) + { + AMQPFastProtocolHandler handler = new AMQPProtocolProvider().getHandler(); + InetSocketAddress bindAddress; + if (bindAddr.equals("wildcard")) + { + bindAddress = new InetSocketAddress(port); + } + else + { + bindAddress = new InetSocketAddress(InetAddress.getByAddress(parseIP(bindAddr)), port); + } + acceptor.setLocalAddress(bindAddress); + acceptor.setHandler(handler); + acceptor.bind(); + _logger.info("Qpid.AMQP listening on non-SSL address " + bindAddress); + } + + if (connectorConfig.enableSSL) + { + AMQPFastProtocolHandler handler = new AMQPProtocolProvider().getHandler(); + handler.setUseSSL(true); + try + { + acceptor.setLocalAddress(new InetSocketAddress(connectorConfig.sslPort)); + acceptor.setHandler(handler); + acceptor.bind(); + _logger.info("Qpid.AMQP listening on SSL port " + connectorConfig.sslPort); + } + catch (IOException e) + { + _logger.error("Unable to listen on SSL port: " + e, e); + } + } + } + catch (Exception e) + { + _logger.error("Unable to bind service to registry: " + e, e); + } + } + + public static void main(String[] args) + { + + new Main(args); + } + + private byte[] parseIP(String address) throws Exception + { + StringTokenizer tokenizer = new StringTokenizer(address, "."); + byte[] ip = new byte[4]; + int index = 0; + while (tokenizer.hasMoreTokens()) + { + String token = tokenizer.nextToken(); + try + { + ip[index++] = Byte.parseByte(token); + } + catch (NumberFormatException e) + { + throw new Exception("Error parsing IP address: " + address, e); + } + } + if (index != 4) + { + throw new Exception("Invalid IP address: " + address); + } + return ip; + } + + private void configureLogging(File logConfigFile, String logWatchConfig) + { + int logWatchTime = 0; + try + { + logWatchTime = Integer.parseInt(logWatchConfig); + } + catch (NumberFormatException e) + { + System.err.println("Log watch configuration value of " + logWatchConfig + " is invalid. Must be " + + "a non-negative integer. Using default of zero (no watching configured"); + } + if (logConfigFile.exists() && logConfigFile.canRead()) + { + System.out.println("Configuring logger using configuration file " + logConfigFile.getAbsolutePath()); + + if (logWatchTime > 0) + { + System.out.println("log file " + logConfigFile.getAbsolutePath() + " will be checked for changes every " + + logWatchTime + " seconds"); + // log4j expects the watch interval in milliseconds + DOMConfigurator.configureAndWatch(logConfigFile.getAbsolutePath(), logWatchTime * 1000); + } + else + { + DOMConfigurator.configure(logConfigFile.getAbsolutePath()); + } + } + else + { + System.err.println("Logging configuration error: unable to read file " + logConfigFile.getAbsolutePath()); + System.err.println("Using basic log4j configuration"); + BasicConfigurator.configure(); + } + } + + private void createAndRegisterBrokerMBean() throws AMQException + { + try + { + new AMQBrokerManager().register(); + } + catch (NotCompliantMBeanException ex) + { + throw new AMQException("Exception occured in creating AMQBrokerManager MBean."); + } + } + + /** + * AMQPBrokerMBean implements the broker management interface and exposes the + * Broker level management features like creating and deleting exchanges and queue. + */ + @MBeanDescription("This MBean exposes the broker level management features") + private final class AMQBrokerManager extends AMQManagedObject + implements ManagedBroker + { + private final QueueRegistry _queueRegistry; + private final ExchangeRegistry _exchangeRegistry; + private final ExchangeFactory _exchangeFactory; + private final MessageStore _messageStore; + + @MBeanConstructor("Creates the Broker Manager MBean") + protected AMQBrokerManager() throws NotCompliantMBeanException + { + super(ManagedBroker.class, ManagedBroker.TYPE); + + IApplicationRegistry appRegistry = ApplicationRegistry.getInstance(); + _queueRegistry = appRegistry.getQueueRegistry(); + _exchangeRegistry = appRegistry.getExchangeRegistry(); + _exchangeFactory = ApplicationRegistry.getInstance().getExchangeFactory(); + _messageStore = ApplicationRegistry.getInstance().getMessageStore(); + } + + public String getObjectInstanceName() + { + return this.getClass().getName(); + } + + /** + * Creates new exchange and registers it with the registry. + * + * @param exchangeName + * @param type + * @param durable + * @param autoDelete + * @throws JMException + */ + public void createNewExchange(String exchangeName, + String type, + boolean durable, + boolean autoDelete) + throws JMException + { + try + { + synchronized(_exchangeRegistry) + { + Exchange exchange = _exchangeRegistry.getExchange(exchangeName); + + if (exchange == null) + { + exchange = _exchangeFactory.createExchange(exchangeName, + type, //eg direct + durable, + autoDelete, + 0); //ticket no + _exchangeRegistry.registerExchange(exchange); + } + else + { + throw new JMException("The exchange \"" + exchangeName + "\" already exists."); + } + } + } + catch (AMQException ex) + { + _logger.error("Error in creating exchange " + exchangeName, ex); + throw new MBeanException(ex, ex.toString()); + } + } + + /** + * Unregisters the exchange from registry. + * + * @param exchangeName + * @throws JMException + */ + public void unregisterExchange(String exchangeName) + throws JMException + { + boolean inUse = false; + // TODO + // Check if the exchange is in use. + // Check if there are queue-bindings with the exchnage and unregister + // when there are no bindings. + try + { + _exchangeRegistry.unregisterExchange(exchangeName, false); + } + catch (AMQException ex) + { + _logger.error("Error in unregistering exchange " + exchangeName, ex); + throw new MBeanException(ex, ex.toString()); + } + } + + /** + * Creates a new queue and registers it with the registry and puts it + * in persistance storage if durable queue. + * + * @param queueName + * @param durable + * @param owner + * @param autoDelete + * @throws JMException + */ + public void createQueue(String queueName, + boolean durable, + String owner, + boolean autoDelete) + throws JMException + { + AMQQueue queue = _queueRegistry.getQueue(queueName); + if (queue == null) + { + try + { + queue = new AMQQueue(queueName, durable, owner, autoDelete, _queueRegistry); + if (queue.isDurable() && !queue.isAutoDelete()) + { + _messageStore.createQueue(queue); + } + _queueRegistry.registerQueue(queue); + } + catch (AMQException ex) + { + _logger.error("Error in creating queue " + queueName, ex); + throw new MBeanException(ex, ex.toString()); + } + } + else + { + throw new JMException("The queue \"" + queueName + "\" already exists."); + } + } + + /** + * Deletes the queue from queue registry and persistant storage. + * + * @param queueName + * @throws JMException + */ + public void deleteQueue(String queueName) throws JMException + { + AMQQueue queue = _queueRegistry.getQueue(queueName); + if (queue == null) + { + throw new JMException("The Queue " + queueName + " is not a registerd queue."); + } + + try + { + queue.delete(); + _messageStore.removeQueue(queueName); + + } + catch (AMQException ex) + { + throw new MBeanException(ex, ex.toString()); + } + } + + public ObjectName getObjectName() throws MalformedObjectNameException + { + StringBuffer objectName = new StringBuffer(ManagedObject.DOMAIN); + objectName.append(":type=").append(getType()); + + return new ObjectName(objectName.toString()); + } + } // End of MBean class +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/ManagedChannel.java b/java/broker/src/main/java/org/apache/qpid/server/ManagedChannel.java new file mode 100644 index 0000000000..74c5366c7d --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/ManagedChannel.java @@ -0,0 +1,67 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +package org.apache.qpid.server; + +import javax.management.JMException; +import java.io.IOException; + +/** + * The managed interface exposed to allow management of channels. + * @author Bhupendra Bhardwaj + * @version 0.1 + */ +public interface ManagedChannel +{ + static final String TYPE = "Channel"; + + /** + * Tells whether the channel is transactional. + * @return true if the channel is transactional. + * @throws IOException + */ + boolean isTransactional() throws IOException; + + /** + * Tells the number of unacknowledged messages in this channel. + * @return number of unacknowledged messages. + * @throws IOException + */ + int getUnacknowledgedMessageCount() throws IOException; + + + //********** Operations *****************// + + /** + * Commits the transactions if the channel is transactional. + * @throws IOException + * @throws JMException + */ + void commitTransactions() throws IOException, JMException; + + /** + * Rollsback the transactions if the channel is transactional. + * @throws IOException + * @throws JMException + */ + void rollbackTransactions() throws IOException, JMException; + +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/RequiredDeliveryException.java b/java/broker/src/main/java/org/apache/qpid/server/RequiredDeliveryException.java new file mode 100644 index 0000000000..87691ccaa3 --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/RequiredDeliveryException.java @@ -0,0 +1,112 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server; + +import org.apache.qpid.framing.BasicPublishBody; +import org.apache.qpid.framing.ContentHeaderBody; +import org.apache.qpid.framing.ContentBody; +import org.apache.qpid.framing.CompositeAMQDataBlock; +import org.apache.qpid.framing.BasicReturnBody; +import org.apache.qpid.framing.AMQFrame; +import org.apache.qpid.AMQException; +import org.apache.qpid.server.queue.AMQMessage; + +import java.util.List; + +/** + * Signals that a required delivery could not be made. This could be bacuse of + * the immediate flag being set and the queue having no consumers, or the mandatory + * flag being set and the exchange having no valid bindings. + */ +public abstract class RequiredDeliveryException extends AMQException +{ + private final String _message; + private final BasicPublishBody _publishBody; + private final ContentHeaderBody _contentHeaderBody; + private final List _contentBodies; + + public RequiredDeliveryException(String message, AMQMessage payload) + { + super(message); + _message = message; + _publishBody = payload.getPublishBody(); + _contentHeaderBody = payload.getContentHeaderBody(); + _contentBodies = payload.getContentBodies(); + } + + public RequiredDeliveryException(String message, + BasicPublishBody publishBody, + ContentHeaderBody contentHeaderBody, + List contentBodies) + { + super(message); + _message = message; + _publishBody = publishBody; + _contentHeaderBody = contentHeaderBody; + _contentBodies = contentBodies; + } + + public BasicPublishBody getPublishBody() + { + return _publishBody; + } + + public ContentHeaderBody getContentHeaderBody() + { + return _contentHeaderBody; + } + + public List getContentBodies() + { + return _contentBodies; + } + + public CompositeAMQDataBlock getReturnMessage(int channel) + { + BasicReturnBody returnBody = new BasicReturnBody(); + returnBody.exchange = _publishBody.exchange; + returnBody.replyCode = getReplyCode(); + returnBody.replyText = _message; + returnBody.routingKey = _publishBody.routingKey; + + AMQFrame[] allFrames = new AMQFrame[2 + _contentBodies.size()]; + + AMQFrame returnFrame = new AMQFrame(); + returnFrame.bodyFrame = returnBody; + returnFrame.channel = channel; + + allFrames[0] = returnFrame; + allFrames[1] = ContentHeaderBody.createAMQFrame(channel, _contentHeaderBody); + for (int i = 2; i < allFrames.length; i++) + { + allFrames[i] = ContentBody.createAMQFrame(channel, _contentBodies.get(i - 2)); + } + + return new CompositeAMQDataBlock(allFrames); + } + + public int getErrorCode() + { + return getReplyCode(); + } + + public abstract int getReplyCode(); +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/ack/TxAck.java b/java/broker/src/main/java/org/apache/qpid/server/ack/TxAck.java new file mode 100644 index 0000000000..a4cb1f1e71 --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/ack/TxAck.java @@ -0,0 +1,132 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.ack; + +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.txn.TxnOp; + +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; + +/** + * A TxnOp implementation for handling accumulated acks + */ +public class TxAck implements TxnOp +{ + private final UnacknowledgedMessageMap _map; + private final List _unacked = new LinkedList(); + private final List _individual = new LinkedList(); + private long _deliveryTag; + private boolean _multiple; + + public TxAck(UnacknowledgedMessageMap map) + { + _map = map; + } + + public void update(long deliveryTag, boolean multiple) + { + if(!multiple) + { + //have acked a single message that is not part of + //the previously acked region so record + //individually + _individual.add(deliveryTag);//_multiple && !multiple + } + else if(deliveryTag > _deliveryTag) + { + //have simply moved the last acked message on a + //bit + _deliveryTag = deliveryTag; + _multiple = true; + } + } + + public void consolidate() + { + //lookup all the unacked messages that have been acked in this transaction + if(_multiple) + { + //get all the unacked messages for the accumulated + //multiple acks + _map.collect(_deliveryTag, true, _unacked); + } + //get any unacked messages for individual acks outside the + //range covered by multiple acks + for(long tag : _individual) + { + if(_deliveryTag < tag) + { + _map.collect(tag, false, _unacked); + } + } + } + + public boolean checkPersistent() throws AMQException + { + //if any of the messages in unacked are persistent the txn + //buffer must be marked as persistent: + for(UnacknowledgedMessage msg : _unacked) + { + if(msg.message.isPersistent()) + { + return true; + } + } + return false; + } + + public void prepare() throws AMQException + { + //make persistent changes, i.e. dequeue and decrementReference + for(UnacknowledgedMessage msg : _unacked) + { + msg.discard(); + } + } + + public void undoPrepare() + { + //decrementReference is annoyingly untransactional (due to + //in memory counter) so if we failed in prepare for full + //txn, this op will have to compensate by fixing the count + //in memory (persistent changes will be rolled back by store) + for(UnacknowledgedMessage msg : _unacked) + { + msg.message.incrementReference(); + } + } + + public void commit() + { + //remove the unacked messages from the channels map + _map.remove(_unacked); + } + + public void rollback() + { + } +} + diff --git a/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessage.java b/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessage.java new file mode 100644 index 0000000000..0eff5a3cca --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessage.java @@ -0,0 +1,51 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.ack; + +import org.apache.qpid.AMQException; +import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.queue.AMQQueue; + +public class UnacknowledgedMessage +{ + public final AMQMessage message; + public final String consumerTag; + public final long deliveryTag; + public AMQQueue queue; + + public UnacknowledgedMessage(AMQQueue queue, AMQMessage message, String consumerTag, long deliveryTag) + { + this.queue = queue; + this.message = message; + this.consumerTag = consumerTag; + this.deliveryTag = deliveryTag; + } + + public void discard() throws AMQException + { + if (queue != null) + { + message.dequeue(queue); + } + message.decrementReference(); + } +} + diff --git a/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMap.java b/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMap.java new file mode 100644 index 0000000000..b0bbe224e3 --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMap.java @@ -0,0 +1,30 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.ack; + +import java.util.List; + +public interface UnacknowledgedMessageMap +{ + public void collect(long deliveryTag, boolean multiple, List msgs); + public void remove(List msgs); +} + diff --git a/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java b/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java new file mode 100644 index 0000000000..eda3233e56 --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java @@ -0,0 +1,84 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.ack; + +import java.util.List; +import java.util.Map; + +public class UnacknowledgedMessageMapImpl implements UnacknowledgedMessageMap +{ + private final Object _lock; + private Map _map; + + public UnacknowledgedMessageMapImpl(Object lock, Map map) + { + _lock = lock; + _map = map; + } + + public void collect(long deliveryTag, boolean multiple, List msgs) + { + if (multiple) + { + collect(deliveryTag, msgs); + } + else + { + msgs.add(get(deliveryTag)); + } + + } + + public void remove(List msgs) + { + synchronized(_lock) + { + for(UnacknowledgedMessage msg : msgs) + { + _map.remove(msg.deliveryTag); + } + } + } + + private UnacknowledgedMessage get(long key) + { + synchronized(_lock) + { + return _map.get(key); + } + } + + private void collect(long key, List msgs) + { + synchronized(_lock) + { + for(Map.Entry entry : _map.entrySet()) + { + msgs.add(entry.getValue()); + if (entry.getKey() == key) + { + break; + } + } + } + } +} + diff --git a/java/broker/src/main/java/org/apache/qpid/server/configuration/Configurator.java b/java/broker/src/main/java/org/apache/qpid/server/configuration/Configurator.java new file mode 100644 index 0000000000..5e3ac03ba7 --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/configuration/Configurator.java @@ -0,0 +1,105 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.configuration; + +import org.apache.commons.configuration.Configuration; +import org.apache.log4j.Logger; +import org.apache.qpid.configuration.Configured; +import org.apache.qpid.configuration.PropertyUtils; +import org.apache.qpid.configuration.PropertyException; +import org.apache.qpid.server.registry.ApplicationRegistry; + +import java.lang.reflect.Field; + +/** + * This class contains utilities for populating classes automatically from values pulled from configuration + * files. + */ +public class Configurator +{ + private static final Logger _logger = Logger.getLogger(Configurator.class); + + /** + * Configure a given instance using the application configuration. Note that superclasses are not + * currently configured but this could easily be added if required. + * @param instance the instance to configure + */ + public static void configure(Object instance) + { + final Configuration config = ApplicationRegistry.getInstance().getConfiguration(); + + for (Field f : instance.getClass().getDeclaredFields()) + { + Configured annotation = f.getAnnotation(Configured.class); + if (annotation != null) + { + setValueInField(f, instance, config, annotation); + } + } + } + + private static void setValueInField(Field f, Object instance, Configuration config, Configured annotation) + { + Class fieldClass = f.getType(); + String configPath = annotation.path(); + try + { + if (fieldClass == String.class) + { + String val = config.getString(configPath, annotation.defaultValue()); + val = PropertyUtils.replaceProperties(val); + f.set(instance, val); + } + else if (fieldClass == int.class) + { + int val = config.getInt(configPath, Integer.parseInt(annotation.defaultValue())); + f.setInt(instance, val); + } + else if (fieldClass == long.class) + { + long val = config.getLong(configPath, Long.parseLong(annotation.defaultValue())); + f.setLong(instance, val); + } + else if (fieldClass == double.class) + { + double val = config.getDouble(configPath, Double.parseDouble(annotation.defaultValue())); + f.setDouble(instance, val); + } + else if (fieldClass == boolean.class) + { + boolean val = config.getBoolean(configPath, Boolean.parseBoolean(annotation.defaultValue())); + f.setBoolean(instance, val); + } + else + { + _logger.error("Unsupported field type " + fieldClass + " for " + f + " IGNORING configured value"); + } + } + catch (PropertyException e) + { + _logger.error("Unable to expand property: " + e + " INGORING field " + f, e); + } + catch (IllegalAccessException e) + { + _logger.error("Unable to access field " + f + " IGNORING configured value"); + } + } +} \ No newline at end of file diff --git a/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java b/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java new file mode 100644 index 0000000000..9ecbf3d31a --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java @@ -0,0 +1,220 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.configuration; + +import org.apache.qpid.url.AMQBindingURL; +import org.apache.qpid.url.URLSyntaxException; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.queue.QueueRegistry; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.exchange.ExchangeRegistry; +import org.apache.qpid.server.store.MessageStore; +import org.apache.qpid.AMQException; +import org.apache.log4j.Logger; +import org.apache.commons.configuration.ConfigurationException; +import org.apache.commons.configuration.XMLConfiguration; + + +import java.util.Collection; + +public class VirtualHostConfiguration +{ + private static final Logger _logger = Logger.getLogger(VirtualHostConfiguration.class); + + XMLConfiguration _config; + + private static final String XML_VIRTUALHOST = "virtualhost"; + private static final String XML_PATH = "path"; + private static final String XML_BIND = "bind"; + private static final String XML_VIRTUALHOST_PATH = "virtualhost.path"; + private static final String XML_VIRTUALHOST_BIND = "virtualhost.bind"; + + + public VirtualHostConfiguration(String configFile) throws ConfigurationException + { + _logger.info("Loading Config file:" + configFile); + + _config = new XMLConfiguration(configFile); + + if (_config.getProperty(XML_VIRTUALHOST_PATH) == null) + { + throw new ConfigurationException( + "Virtualhost Configuration document does not contain a valid virtualhost."); + } + } + + public void performBindings() throws AMQException, ConfigurationException, URLSyntaxException + { + Object prop = _config.getProperty(XML_VIRTUALHOST_PATH); + + if (prop instanceof Collection) + { + _logger.debug("Number of VirtualHosts: " + ((Collection) prop).size()); + + int virtualhosts = ((Collection) prop).size(); + for (int vhost = 0; vhost < virtualhosts; vhost++) + { + loadVirtualHost(vhost); + } + } + else + { + loadVirtualHost(-1); + } + } + + private void loadVirtualHost(int index) throws AMQException, ConfigurationException, URLSyntaxException + { + String path = XML_VIRTUALHOST; + + if (index != -1) + { + path = path + "(" + index + ")"; + } + + Object prop = _config.getProperty(path + "." + XML_PATH); + + if (prop == null) + { + prop = _config.getProperty(path + "." + XML_BIND); + String error = "Virtual Host not defined for binding"; + + if (prop != null) + { + if (prop instanceof Collection) + { + error += "s"; + } + + error += ": " + prop; + } + + throw new ConfigurationException(error); + } + + _logger.info("VirtualHost:'" + prop + "'"); + + prop = _config.getProperty(path + "." + XML_BIND); + if (prop instanceof Collection) + { + int bindings = ((Collection) prop).size(); + _logger.debug("Number of Bindings: " + bindings); + for (int dest = 0; dest < bindings; dest++) + { + loadBinding(path, dest); + } + } + else + { + loadBinding(path, -1); + } + } + + private void loadBinding(String rootpath, int index) throws AMQException, ConfigurationException, URLSyntaxException + { + String path = rootpath + "." + XML_BIND; + if (index != -1) + { + path = path + "(" + index + ")"; + } + + String bindingString = _config.getString(path); + + AMQBindingURL binding = new AMQBindingURL(bindingString); + + _logger.debug("Loaded Binding:" + binding); + + try + { + bind(binding); + } + catch (AMQException amqe) + { + _logger.info("Unable to bind url: " + binding); + throw amqe; + } + } + + private void bind(AMQBindingURL binding) throws AMQException, ConfigurationException + { + + String queueName = binding.getQueueName(); + + // This will occur if the URL is a Topic + if (queueName == null) + { + //todo register valid topic + ///queueName = binding.getDestinationName(); + throw new AMQException("Topics cannot be bound. TODO Register valid topic"); + } + + //Get references to Broker Registries + QueueRegistry queueRegistry = ApplicationRegistry.getInstance().getQueueRegistry(); + MessageStore messageStore = ApplicationRegistry.getInstance().getMessageStore(); + ExchangeRegistry exchangeRegistry = ApplicationRegistry.getInstance().getExchangeRegistry(); + + synchronized (queueRegistry) + { + AMQQueue queue = queueRegistry.getQueue(queueName); + + if (queue == null) + { + _logger.info("Queue '" + binding.getQueueName() + "' does not exists. Creating."); + + queue = new AMQQueue(queueName, + Boolean.parseBoolean(binding.getOption(AMQBindingURL.OPTION_DURABLE)), + null /* These queues will have no owner */, + false /* Therefore autodelete makes no sence */, queueRegistry); + + if (queue.isDurable()) + { + messageStore.createQueue(queue); + } + + queueRegistry.registerQueue(queue); + } + else + { + _logger.info("Queue '" + binding.getQueueName() + "' already exists not creating."); + } + + Exchange defaultExchange = exchangeRegistry.getExchange(binding.getExchangeName()); + synchronized (defaultExchange) + { + if (defaultExchange == null) + { + throw new ConfigurationException("Attempt to bind queue to unknown exchange:" + binding); + } + + defaultExchange.registerQueue(queue.getName(), queue, null); + + if (binding.getRoutingKey() == null || binding.getRoutingKey().equals("")) + { + throw new ConfigurationException("Unknown binding not specified on url:" + binding); + } + + queue.bind(binding.getRoutingKey(), defaultExchange); + } + _logger.info("Queue '" + queue.getName() + "' bound to exchange:" + binding.getExchangeName() + " RK:'" + binding.getRoutingKey() + "'"); + } + } +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java b/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java new file mode 100644 index 0000000000..69f5e862d6 --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java @@ -0,0 +1,139 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.exchange; + +import org.apache.qpid.AMQException; +import org.apache.qpid.server.management.AMQManagedObject; +import org.apache.qpid.server.management.Managable; +import org.apache.qpid.server.management.ManagedObject; + +import javax.management.NotCompliantMBeanException; + +public abstract class AbstractExchange implements Exchange, Managable +{ + private String _name; + + protected boolean _durable; + + protected int _ticket; + + protected ExchangeMBean _exchangeMbean; + + /** + * Whether the exchange is automatically deleted once all queues have detached from it + */ + protected boolean _autoDelete; + + /** + * Abstract MBean class. This has some of the methods implemented from + * management intrerface for exchanges. Any implementaion of an + * Exchange MBean should extend this class. + */ + protected abstract class ExchangeMBean extends AMQManagedObject implements ManagedExchange + { + public ExchangeMBean() throws NotCompliantMBeanException + { + super(ManagedExchange.class, ManagedExchange.TYPE); + } + + public String getObjectInstanceName() + { + return _name; + } + + public String getName() + { + return _name; + } + + public Integer getTicketNo() + { + return _ticket; + } + + public boolean isDurable() + { + return _durable; + } + + public boolean isAutoDelete() + { + return _autoDelete; + } + + } // End of MBean class + + public String getName() + { + return _name; + } + + /** + * Concrete exchanges must implement this method in order to create the managed representation. This is + * called during initialisation (template method pattern). + * @return the MBean + */ + protected abstract ExchangeMBean createMBean() throws AMQException; + + public void initialise(String name, boolean durable, int ticket, boolean autoDelete) throws AMQException + { + _name = name; + _durable = durable; + _autoDelete = autoDelete; + _ticket = ticket; + _exchangeMbean = createMBean(); + _exchangeMbean.register(); + } + + public boolean isDurable() + { + return _durable; + } + + public boolean isAutoDelete() + { + return _autoDelete; + } + + public int getTicket() + { + return _ticket; + } + + public void close() throws AMQException + { + if (_exchangeMbean != null) + { + _exchangeMbean.unregister(); + } + } + + public String toString() + { + return getClass().getName() + "[" + getName() +"]"; + } + + public ManagedObject getManagedObject() + { + return _exchangeMbean; + } + +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java b/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java new file mode 100644 index 0000000000..0c73e0f9f0 --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java @@ -0,0 +1,66 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.exchange; + +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; + +import java.util.HashMap; +import java.util.Map; + +public class DefaultExchangeFactory implements ExchangeFactory +{ + private static final Logger _logger = Logger.getLogger(DefaultExchangeFactory.class); + + private Map> _exchangeClassMap = new HashMap>(); + + public DefaultExchangeFactory() + { + _exchangeClassMap.put("direct", org.apache.qpid.server.exchange.DestNameExchange.class); + _exchangeClassMap.put("topic", org.apache.qpid.server.exchange.DestWildExchange.class); + _exchangeClassMap.put("headers", org.apache.qpid.server.exchange.HeadersExchange.class); + } + + public Exchange createExchange(String exchange, String type, boolean durable, boolean autoDelete, + int ticket) + throws AMQException + { + Class exchClass = _exchangeClassMap.get(type); + if (exchClass == null) + { + throw new AMQException(_logger, "Unknown exchange type: " + type); + } + try + { + Exchange e = exchClass.newInstance(); + e.initialise(exchange, durable, ticket, autoDelete); + return e; + } + catch (InstantiationException e) + { + throw new AMQException(_logger, "Unable to create exchange: " + e, e); + } + catch (IllegalAccessException e) + { + throw new AMQException(_logger, "Unable to create exchange: " + e, e); + } + } +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java b/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java new file mode 100644 index 0000000000..eb9d1acb59 --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java @@ -0,0 +1,95 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.exchange; + +import org.apache.qpid.AMQException; +import org.apache.qpid.server.protocol.ExchangeInitialiser; +import org.apache.qpid.server.queue.AMQMessage; +import org.apache.log4j.Logger; + +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +public class DefaultExchangeRegistry implements ExchangeRegistry +{ + private static final Logger _log = Logger.getLogger(DefaultExchangeRegistry.class); + + /** + * Maps from exchange name to exchange instance + */ + private ConcurrentMap _exchangeMap = new ConcurrentHashMap(); + + public DefaultExchangeRegistry(ExchangeFactory exchangeFactory) + { + //create 'standard' exchanges: + try + { + new ExchangeInitialiser().initialise(exchangeFactory, this); + } + catch(AMQException e) + { + _log.error("Failed to initialise exchanges: ", e); + } + } + + public void registerExchange(Exchange exchange) + { + _exchangeMap.put(exchange.getName(), exchange); + } + + public void unregisterExchange(String name, boolean inUse) throws AMQException + { + // TODO: check inUse argument + Exchange e = _exchangeMap.remove(name); + if (e != null) + { + e.close(); + } + else + { + throw new AMQException("Unknown exchange " + name); + } + } + + public Exchange getExchange(String name) + { + return _exchangeMap.get(name); + } + + /** + * Routes content through exchanges, delivering it to 1 or more queues. + * @param payload + * @throws AMQException if something goes wrong delivering data + */ + public void routeContent(AMQMessage payload) throws AMQException + { + final String exchange = payload.getPublishBody().exchange; + final Exchange exch = _exchangeMap.get(exchange); + // there is a small window of opportunity for the exchange to be deleted in between + // the JmsPublish being received (where the exchange is validated) and the final + // content body being received (which triggers this method) + if (exch == null) + { + throw new AMQException("Exchange '" + exchange + "' does not exist"); + } + exch.route(payload); + } +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/exchange/DestNameExchange.java b/java/broker/src/main/java/org/apache/qpid/server/exchange/DestNameExchange.java new file mode 100644 index 0000000000..085d0aad19 --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/exchange/DestNameExchange.java @@ -0,0 +1,223 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.exchange; + +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.BasicPublishBody; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.server.management.MBeanDescription; +import org.apache.qpid.server.management.MBeanConstructor; +import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.registry.ApplicationRegistry; + +import javax.management.JMException; +import javax.management.MBeanException; +import javax.management.NotCompliantMBeanException; +import javax.management.openmbean.*; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +public class DestNameExchange extends AbstractExchange +{ + private static final Logger _logger = Logger.getLogger(DestNameExchange.class); + + /** + * Maps from queue name to queue instances + */ + private final Index _index = new Index(); + + /** + * MBean class implementing the management interfaces. + */ + @MBeanDescription("Management Bean for Direct Exchange") + private final class DestNameExchangeMBean extends ExchangeMBean + { + private String[] _bindingItemNames = {"BindingKey", "QueueNames"}; + private String[] _bindingItemDescriptions = {"Binding key", "Queue Names"}; + private String[] _bindingItemIndexNames = {"BindingKey"}; + private OpenType[] _bindingItemTypes = new OpenType[2]; + + private CompositeType _bindingDataType = null; + private TabularType _bindinglistDataType = null; + private TabularDataSupport _bindingList = null; + + @MBeanConstructor("Creates an MBean for AMQ direct exchange") + public DestNameExchangeMBean() throws NotCompliantMBeanException + { + super(); + init(); + } + + /** + * initialises the OpenType objects. + */ + private void init() + { + try + { + _bindingItemTypes[0] = SimpleType.STRING; + //_bindingItemTypes[1] = ArrayType.getArrayType(SimpleType.STRING); + _bindingItemTypes[1] = new ArrayType(1, SimpleType.STRING); + + _bindingDataType = new CompositeType("QueueBinding", + "Binding key and bound Queue names", + _bindingItemNames, + _bindingItemDescriptions, + _bindingItemTypes); + _bindinglistDataType = new TabularType("Bindings", + "List of queue bindings for " + getName() , + _bindingDataType, + _bindingItemIndexNames); + } + catch(OpenDataException ex) + { + //It should never occur. + _logger.error("OpenDataTypes could not be created.", ex); + throw new RuntimeException(ex); + } + } + + public TabularData viewBindings() + throws OpenDataException + { + Map> bindings = _index.getBindingsMap(); + _bindingList = new TabularDataSupport(_bindinglistDataType); + + for (Map.Entry> entry : bindings.entrySet()) + { + String key = entry.getKey(); + List queueList = new ArrayList(); + + List queues = entry.getValue(); + for (AMQQueue q : queues) + { + queueList.add(q.getName()); + } + + Object[] bindingItemValues = {key, queueList.toArray(new String[0])}; + CompositeData bindingData = new CompositeDataSupport(_bindingDataType, + _bindingItemNames, + bindingItemValues); + _bindingList.put(bindingData); + } + + return _bindingList; + } + + public void createBinding(String queueName, String binding) + throws JMException + { + AMQQueue queue = ApplicationRegistry.getInstance().getQueueRegistry().getQueue(queueName); + + if (queue == null) + { + throw new JMException("Queue \"" + queueName + "\" is not registered with the exchange."); + } + + try + { + registerQueue(binding, queue, null); + queue.bind(binding, DestNameExchange.this); + } + catch (AMQException ex) + { + throw new MBeanException(ex); + } + } + + }// End of MBean class + + + protected ExchangeMBean createMBean() throws AMQException + { + try + { + return new DestNameExchangeMBean(); + } + catch (NotCompliantMBeanException ex) + { + _logger.error("Exception occured in creating the DestNameExchenge", ex); + throw new AMQException("Exception occured in creating the DestNameExchenge", ex); + } + } + + public void registerQueue(String routingKey, AMQQueue queue, FieldTable args) throws AMQException + { + assert queue != null; + assert routingKey != null; + if (!_index.add(routingKey, queue)) + { + _logger.debug("Queue " + queue + " is already registered with routing key " + routingKey); + } + else + { + _logger.debug("Binding queue " + queue + " with routing key " + routingKey + + " to exchange " + this); + } + } + + public void deregisterQueue(String routingKey, AMQQueue queue) throws AMQException + { + assert queue != null; + assert routingKey != null; + + if (!_index.remove(routingKey, queue)) + { + throw new AMQException("Queue " + queue + " was not registered with exchange " + this.getName() + + " with routing key " + routingKey + ". No queue was registered with that routing key"); + } + } + + public void route(AMQMessage payload) throws AMQException + { + BasicPublishBody publishBody = payload.getPublishBody(); + + final String routingKey = publishBody.routingKey; + final List queues = _index.get(routingKey); + if (queues == null || queues.isEmpty()) + { + String msg = "Routing key " + routingKey + " is not known to " + this; + if (publishBody.mandatory) + { + throw new NoRouteException(msg, payload); + } + else + { + _logger.warn(msg); + } + } + else + { + if (_logger.isDebugEnabled()) + { + _logger.debug("Publishing message to queue " + queues); + } + + for (AMQQueue q : queues) + { + q.deliver(payload); + } + } + } +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/exchange/DestWildExchange.java b/java/broker/src/main/java/org/apache/qpid/server/exchange/DestWildExchange.java new file mode 100644 index 0000000000..f6abd53076 --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/exchange/DestWildExchange.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.server.exchange; + +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.framing.BasicPublishBody; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.management.MBeanDescription; +import org.apache.qpid.server.management.MBeanConstructor; + +import javax.management.openmbean.*; +import javax.management.JMException; +import javax.management.MBeanException; +import javax.management.NotCompliantMBeanException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArrayList; + +public class DestWildExchange extends AbstractExchange +{ + private static final Logger _logger = Logger.getLogger(DestWildExchange.class); + + private ConcurrentHashMap> _routingKey2queues = new ConcurrentHashMap>(); + + /** + * DestWildExchangeMBean class implements the management interface for the + * Topic exchanges. + */ + @MBeanDescription("Management Bean for Topic Exchange") + private final class DestWildExchangeMBean extends ExchangeMBean + { + private String[] _bindingItemNames = {"BindingKey", "QueueNames"}; + private String[] _bindingItemDescriptions = {"Binding key", "Queue Names"}; + private String[] _bindingItemIndexNames = {"BindingKey"}; + private OpenType[] _bindingItemTypes = new OpenType[2]; + + private CompositeType _bindingDataType = null; + private TabularType _bindinglistDataType = null; + private TabularDataSupport _bindingList = null; + + @MBeanConstructor("Creates an MBean for AMQ topic exchange") + public DestWildExchangeMBean() throws NotCompliantMBeanException + { + super(); + init(); + } + + /** + * initialises the OpenType objects. + */ + private void init() + { + try + { + _bindingItemTypes[0] = SimpleType.STRING; + _bindingItemTypes[1] = new ArrayType(1, SimpleType.STRING); + + _bindingDataType = new CompositeType("QueueBinding", + "Binding key and bound Queue names", + _bindingItemNames, + _bindingItemDescriptions, + _bindingItemTypes); + _bindinglistDataType = new TabularType("Bindings", + "List of queue bindings for " + getName(), + _bindingDataType, + _bindingItemIndexNames); + } + catch(OpenDataException ex) + { + //It should never occur. + _logger.error("OpenDataTypes could not be created.", ex); + throw new RuntimeException(ex); + } + } + + public TabularData viewBindings() + throws OpenDataException + { + _bindingList = new TabularDataSupport(_bindinglistDataType); + + for (Map.Entry> entry : _routingKey2queues.entrySet()) + { + String key = entry.getKey(); + List queueList = new ArrayList(); + + List queues = entry.getValue(); + for (AMQQueue q : queues) + { + queueList.add(q.getName()); + } + + Object[] bindingItemValues = {key, queueList.toArray(new String[0])}; + CompositeData bindingData = new CompositeDataSupport(_bindingDataType, + _bindingItemNames, + bindingItemValues); + _bindingList.put(bindingData); + } + + return _bindingList; + } + + public void createBinding(String queueName, String binding) + throws JMException + { + AMQQueue queue = ApplicationRegistry.getInstance().getQueueRegistry().getQueue(queueName); + + if (queue == null) + throw new JMException("Queue \"" + queueName + "\" is not registered with the exchange."); + + try + { + registerQueue(binding, queue, null); + queue.bind(binding, DestWildExchange.this); + } + catch (AMQException ex) + { + throw new MBeanException(ex); + } + } + + } // End of MBean class + + + public void registerQueue(String routingKey, AMQQueue queue, FieldTable args) throws AMQException + { + assert queue != null; + assert routingKey != null; + // we need to use putIfAbsent, which is an atomic operation, to avoid a race condition + List queueList = _routingKey2queues.putIfAbsent(routingKey, new CopyOnWriteArrayList()); + // if we got null back, no previous value was associated with the specified routing key hence + // we need to read back the new value just put into the map + if (queueList == null) + { + queueList = _routingKey2queues.get(routingKey); + } + if (!queueList.contains(queue)) + { + queueList.add(queue); + } + else if(_logger.isDebugEnabled()) + { + _logger.debug("Queue " + queue + " is already registered with routing key " + routingKey); + } + + } + + public void route(AMQMessage payload) throws AMQException + { + BasicPublishBody publishBody = payload.getPublishBody(); + + final String routingKey = publishBody.routingKey; + List queues = _routingKey2queues.get(routingKey); + // if we have no registered queues we have nothing to do + // TODO: add support for the immediate flag + if (queues == null) + { + //todo Check for valid topic - mritchie + return; + } + + for (AMQQueue q : queues) + { + // TODO: modify code generator to add clone() method then clone the deliver body + // without this addition we have a race condition - we will be modifying the body + // before the encoder has encoded the body for delivery + q.deliver(payload); + } + } + + public void deregisterQueue(String routingKey, AMQQueue queue) throws AMQException + { + assert queue != null; + assert routingKey != null; + + List queues = _routingKey2queues.get(routingKey); + if (queues == null) + { + throw new AMQException("Queue " + queue + " was not registered with exchange " + this.getName() + + " with routing key " + routingKey + ". No queue was registered with that routing key"); + + } + boolean removedQ = queues.remove(queue); + if (!removedQ) + { + throw new AMQException("Queue " + queue + " was not registered with exchange " + this.getName() + + " with routing key " + routingKey); + } + } + + protected ExchangeMBean createMBean() throws AMQException + { + try + { + return new DestWildExchangeMBean(); + } + catch (NotCompliantMBeanException ex) + { + _logger.error("Exception occured in creating the DestWildExchenge", ex); + throw new AMQException("Exception occured in creating the DestWildExchenge", ex); + } + } +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java b/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java new file mode 100644 index 0000000000..787d0eddfd --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java @@ -0,0 +1,50 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.exchange; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.queue.AMQMessage; + +public interface Exchange +{ + String getName(); + + void initialise(String name, boolean durable, int ticket, boolean autoDelete) throws AMQException; + + boolean isDurable(); + + /** + * @return true if the exchange will be deleted after all queues have been detached + */ + boolean isAutoDelete(); + + int getTicket(); + + void close() throws AMQException; + + void registerQueue(String routingKey, AMQQueue queue, FieldTable args) throws AMQException; + + void deregisterQueue(String routingKey, AMQQueue queue) throws AMQException; + + void route(AMQMessage message) throws AMQException; +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeFactory.java b/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeFactory.java new file mode 100644 index 0000000000..37ba883bc3 --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeFactory.java @@ -0,0 +1,31 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.exchange; + +import org.apache.qpid.AMQException; + + +public interface ExchangeFactory +{ + Exchange createExchange(String exchange, String type, boolean durable, boolean autoDelete, + int ticket) + throws AMQException; +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeInUseException.java b/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeInUseException.java new file mode 100644 index 0000000000..6b2891c573 --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeInUseException.java @@ -0,0 +1,31 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.exchange; + +import org.apache.qpid.AMQException; + +public class ExchangeInUseException extends AMQException +{ + public ExchangeInUseException(String exchangeName) + { + super("Exchange " + exchangeName + " is currently in use"); + } +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeRegistry.java b/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeRegistry.java new file mode 100644 index 0000000000..dcc50a796a --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeRegistry.java @@ -0,0 +1,41 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.exchange; + +import org.apache.qpid.AMQException; +import org.apache.qpid.server.queue.AMQMessage; + + +public interface ExchangeRegistry extends MessageRouter +{ + void registerExchange(Exchange exchange); + + /** + * Unregister an exchange + * @param name name of the exchange to delete + * @param inUse if true, do NOT delete the exchange if it is in use (has queues bound to it) + * @throws ExchangeInUseException when the exchange cannot be deleted because it is in use + * @throws AMQException + */ + void unregisterExchange(String name, boolean inUse) throws ExchangeInUseException, AMQException; + + Exchange getExchange(String name); +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersBinding.java b/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersBinding.java new file mode 100644 index 0000000000..b058211288 --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersBinding.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.server.exchange; + +import org.apache.log4j.Logger; + +import java.util.Collections; +import java.util.Map; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Set; + +/** + * Defines binding and matching based on a set of headers. + */ +class HeadersBinding +{ + private static final Logger _logger = Logger.getLogger(HeadersBinding.class); + + private final Map _mappings = new HashMap(); + private final Set required = new HashSet(); + private final Set matches = new HashSet(); + private boolean matchAny; + + /** + * Creates a binding for a set of mappings. Those mappings whose value is + * null or the empty string are assumed only to be required headers, with + * no constraint on the value. Those with a non-null value are assumed to + * define a required match of value. + * @param mappings the defined mappings this binding should use + */ + HeadersBinding(Map mappings) + { + //noinspection unchecked + this(mappings == null ? new HashSet() : mappings.entrySet()); + _mappings.putAll(mappings); + } + + private HeadersBinding(Set entries) + { + for (Map.Entry e : entries) + { + if (isSpecial(e.getKey())) + { + processSpecial((String) e.getKey(), e.getValue()); + } + else if (e.getValue() == null || e.getValue().equals("")) + { + required.add(e.getKey()); + } + else + { + matches.add(e); + } + } + } + + protected Map getMappings() + { + return _mappings; + } + + /** + * Checks whether the supplied headers match the requirements of this binding + * @param headers the headers to check + * @return true if the headers define any required keys and match any required + * values + */ + public boolean matches(Map headers) + { + if(headers == null) + { + return required.isEmpty() && matches.isEmpty(); + } + else + { + return matchAny ? or(headers) : and(headers); + } + } + + private boolean and(Map headers) + { + //need to match all the defined mapping rules: + return headers.keySet().containsAll(required) + && headers.entrySet().containsAll(matches); + } + + private boolean or(Map headers) + { + //only need to match one mapping rule: + return !Collections.disjoint(headers.keySet(), required) + || !Collections.disjoint(headers.entrySet(), matches); + } + + private void processSpecial(String key, Object value) + { + if("X-match".equalsIgnoreCase(key)) + { + matchAny = isAny(value); + } + else + { + _logger.warn("Ignoring special header: " + key); + } + } + + private boolean isAny(Object value) + { + if(value instanceof String) + { + if("any".equalsIgnoreCase((String) value)) return true; + if("all".equalsIgnoreCase((String) value)) return false; + } + _logger.warn("Ignoring unrecognised match type: " + value); + return false;//default to all + } + + static boolean isSpecial(Object key) + { + return key instanceof String && isSpecial((String) key); + } + + static boolean isSpecial(String key) + { + return key.startsWith("X-") || key.startsWith("x-"); + } +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java b/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java new file mode 100644 index 0000000000..961d4ddf4c --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.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.server.exchange; + +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.BasicContentHeaderProperties; +import org.apache.qpid.framing.ContentHeaderBody; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.server.management.MBeanConstructor; +import org.apache.qpid.server.management.MBeanDescription; +import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.registry.ApplicationRegistry; + +import javax.management.JMException; +import javax.management.NotCompliantMBeanException; +import javax.management.openmbean.*; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CopyOnWriteArrayList; + +/** + * An exchange that binds queues based on a set of required headers and header values + * and routes messages to these queues by matching the headers of the message against + * those with which the queues were bound. + *

+ *

+ * The Headers Exchange
+ *
+ *  Routes messages according to the value/presence of fields in the message header table.
+ *  (Basic and JMS content has a content header field called "headers" that is a table of
+ *   message header fields).
+ *
+ *  class = "headers"
+ *  routing key is not used
+ *
+ *  Has the following binding arguments:
+ *
+ *  the X-match field - if "all", does an AND match (used for GRM), if "any", does an OR match.
+ *  other fields prefixed with "X-" are ignored (and generate a console warning message).
+ *  a field with no value or empty value indicates a match on presence only.
+ *  a field with a value indicates match on field presence and specific value.
+ *
+ *  Standard instances:
+ *
+ *  amq.match - pub/sub on field content/value
+ *  
+ */ +public class HeadersExchange extends AbstractExchange +{ + private static final Logger _logger = Logger.getLogger(HeadersExchange.class); + + private final List _bindings = new CopyOnWriteArrayList(); + + /** + * HeadersExchangeMBean class implements the management interface for the + * Header Exchanges. + */ + @MBeanDescription("Management Bean for Headers Exchange") + private final class HeadersExchangeMBean extends ExchangeMBean + { + private String[] _bindingItemNames = {"Queue", "HeaderBinding"}; + private String[] _bindingItemDescriptions = {"Queue Name", "Header attribute bindings"}; + private String[] _bindingItemIndexNames = {"HeaderBinding"}; + private OpenType[] _bindingItemTypes = new OpenType[2]; + + private CompositeType _bindingDataType = null; + private TabularType _bindinglistDataType = null; + private TabularDataSupport _bindingList = null; + + @MBeanConstructor("Creates an MBean for AMQ Headers exchange") + public HeadersExchangeMBean() throws NotCompliantMBeanException + { + super(); + init(); + } + /** + * initialises the OpenType objects. + */ + private void init() + { + try + { + _bindingItemTypes[0] = SimpleType.STRING; + _bindingItemTypes[1] = new ArrayType(1, SimpleType.STRING); + + _bindingDataType = new CompositeType("QueueAndHeaderAttributesBinding", + "Queue name and header bindings", + _bindingItemNames, + _bindingItemDescriptions, + _bindingItemTypes); + _bindinglistDataType = new TabularType("HeaderBindings", + "List of queue bindings for " + getName(), + _bindingDataType, + _bindingItemIndexNames); + } + catch(OpenDataException ex) + { + //It should never occur. + _logger.error("OpenDataTypes could not be created.", ex); + throw new RuntimeException(ex); + } + } + + public TabularData viewBindings() + throws OpenDataException + { + _bindingList = new TabularDataSupport(_bindinglistDataType); + for (Iterator itr = _bindings.iterator(); itr.hasNext();) + { + Registration registration = itr.next(); + String queueName = registration.queue.getName(); + + HeadersBinding headers = registration.binding; + Map headerMappings = headers.getMappings(); + List mappingList = new ArrayList(); + + for (Map.Entry en : headerMappings.entrySet()) + { + String key = en.getKey().toString(); + String value = en.getValue().toString(); + + mappingList.add(key + "=" + value); + } + + Object[] bindingItemValues = {queueName, mappingList.toArray(new String[0])}; + CompositeData bindingData = new CompositeDataSupport(_bindingDataType, + _bindingItemNames, + bindingItemValues); + _bindingList.put(bindingData); + } + + return _bindingList; + } + + /** + * Creates bindings. Binding pattern is as follows- + * =,=,... + * @param queueName + * @param binding + * @throws JMException + */ + public void createBinding(String queueName, String binding) + throws JMException + { + AMQQueue queue = ApplicationRegistry.getInstance().getQueueRegistry().getQueue(queueName); + + if (queue == null) + { + throw new JMException("Queue \"" + queueName + "\" is not registered with the exchange."); + } + + String[] bindings = binding.split(","); + FieldTable fieldTable = new FieldTable(); + for (int i = 0; i < bindings.length; i++) + { + String[] keyAndValue = bindings[i].split("="); + if (keyAndValue == null || keyAndValue.length < 2) + { + throw new JMException("Format for headers binding should be \"=,=\" "); + } + fieldTable.put(keyAndValue[0], keyAndValue[1]); + } + + _bindings.add(new Registration(new HeadersBinding(fieldTable), queue)); + } + + } // End of MBean class + + public void registerQueue(String routingKey, AMQQueue queue, FieldTable args) throws AMQException + { + _logger.debug("Exchange " + getName() + ": Binding " + queue.getName() + " with " + args); + _bindings.add(new Registration(new HeadersBinding(args), queue)); + } + + public void deregisterQueue(String routingKey, AMQQueue queue) throws AMQException + { + _logger.debug("Exchange " + getName() + ": Unbinding " + queue.getName()); + _bindings.remove(new Registration(null, queue)); + } + + public void route(AMQMessage payload) throws AMQException + { + Map headers = getHeaders(payload.getContentHeaderBody()); + if (_logger.isDebugEnabled()) + { + _logger.debug("Exchange " + getName() + ": routing message with headers " + headers); + } + boolean delivered = false; + for (Registration e : _bindings) + { + if (e.binding.matches(headers)) + { + if (_logger.isDebugEnabled()) + { + _logger.debug("Exchange " + getName() + ": delivering message with headers " + + headers + " to " + e.queue.getName()); + } + e.queue.deliver(payload); + delivered = true; + } + } + if (!delivered) + { + _logger.warn("Exchange " + getName() + ": message not routable."); + } + } + + protected Map getHeaders(ContentHeaderBody contentHeaderFrame) + { + //what if the content type is not 'basic'? 'file' and 'stream' content classes also define headers, + //but these are not yet implemented. + return ((BasicContentHeaderProperties) contentHeaderFrame.properties).getHeaders(); + } + + protected ExchangeMBean createMBean() throws AMQException + { + try + { + return new HeadersExchangeMBean(); + } + catch (NotCompliantMBeanException ex) + { + _logger.error("Exception occured in creating the HeadersExchangeMBean", ex); + throw new AMQException("Exception occured in creating the HeadersExchangeMBean", ex); + } + } + + private static class Registration + { + private final HeadersBinding binding; + private final AMQQueue queue; + + Registration(HeadersBinding binding, AMQQueue queue) + { + this.binding = binding; + this.queue = queue; + } + + public int hashCode() + { + return queue.hashCode(); + } + + public boolean equals(Object o) + { + return o instanceof Registration && ((Registration) o).queue.equals(queue); + } + } +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/exchange/Index.java b/java/broker/src/main/java/org/apache/qpid/server/exchange/Index.java new file mode 100644 index 0000000000..fb48729c9e --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/exchange/Index.java @@ -0,0 +1,88 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.exchange; + +import org.apache.qpid.server.queue.AMQQueue; + +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.CopyOnWriteArrayList; + +/** + * An index of queues against routing key. Allows multiple queues to be stored + * against the same key. Used in the DestNameExchange. + */ +class Index +{ + private ConcurrentMap> _index + = new ConcurrentHashMap>(); + + boolean add(String key, AMQQueue queue) + { + List queues = _index.get(key); + if(queues == null) + { + queues = new CopyOnWriteArrayList(); + //next call is atomic, so there is no race to create the list + List active = _index.putIfAbsent(key, queues); + if(active != null) + { + //someone added the new one in faster than we did, so use theirs + queues = active; + } + } + if(queues.contains(queue)) + { + return false; + } + else + { + return queues.add(queue); + } + } + + boolean remove(String key, AMQQueue queue) + { + List queues = _index.get(key); + if (queues != null) + { + boolean removed = queues.remove(queue); + if (queues.size() == 0) + { + _index.remove(key); + } + return removed; + } + return false; + } + + List get(String key) + { + return _index.get(key); + } + + Map> getBindingsMap() + { + return _index; + } +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/exchange/ManagedExchange.java b/java/broker/src/main/java/org/apache/qpid/server/exchange/ManagedExchange.java new file mode 100644 index 0000000000..3c2c105186 --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/exchange/ManagedExchange.java @@ -0,0 +1,93 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.exchange; + +import org.apache.qpid.server.management.MBeanAttribute; +import org.apache.qpid.server.management.MBeanOperation; +import org.apache.qpid.server.management.MBeanOperationParameter; + +import javax.management.openmbean.TabularData; +import javax.management.JMException; +import javax.management.MBeanOperationInfo; +import java.io.IOException; + +/** + * The management interface exposed to allow management of an Exchange. + * @author Robert J. Greig + * @author Bhupendra Bhardwaj + * @version 0.1 + */ +public interface ManagedExchange +{ + static final String TYPE = "Exchange"; + + /** + * Returns the name of the managed exchange. + * @return the name of the exchange. + * @throws IOException + */ + @MBeanAttribute(name="Name", description="Name of exchange") + String getName() throws IOException; + + @MBeanAttribute(name="TicketNo", description="Exchange Ticket No") + Integer getTicketNo() throws IOException; + + /** + * Tells if the exchange is durable or not. + * @return true if the exchange is durable. + * @throws IOException + */ + @MBeanAttribute(name="Durable", description="true if Exchange is durable") + boolean isDurable() throws IOException; + + /** + * Tells if the exchange is set for autodelete or not. + * @return true if the exchange is set as autodelete. + * @throws IOException + */ + @MBeanAttribute(name="AutoDelete", description="true if Exchange is AutoDelete") + boolean isAutoDelete() throws IOException; + + // Operations + + /** + * Returns all the bindings this exchange has with the queues. + * @return the bindings with the exchange. + * @throws IOException + * @throws JMException + */ + @MBeanOperation(name="viewBindings", description="view the queue bindings for this exchange") + TabularData viewBindings() throws IOException, JMException; + + /** + * Creates new binding with the given queue and binding. + * @param queueName + * @param binding + * @throws JMException + */ + @MBeanOperation(name="createBinding", + description="create a new binding with this exchange", + impact= MBeanOperationInfo.ACTION) + void createBinding(@MBeanOperationParameter(name="queue name", description="queue name") String queueName, + @MBeanOperationParameter(name="binding", description="queue binding")String binding) + throws JMException; + +} \ No newline at end of file diff --git a/java/broker/src/main/java/org/apache/qpid/server/exchange/MessageRouter.java b/java/broker/src/main/java/org/apache/qpid/server/exchange/MessageRouter.java new file mode 100644 index 0000000000..70b80f65da --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/exchange/MessageRouter.java @@ -0,0 +1,39 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.exchange; + +import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.AMQException; + +/** + * Separated out from the ExchangeRegistry interface to allow components + * that use only this part to have a dependency with a reduced footprint. + * + */ +public interface MessageRouter +{ + /** + * Routes content through exchanges, delivering it to 1 or more queues. + * @param message the message to be routed + * @throws org.apache.qpid.AMQException if something goes wrong delivering data + */ + void routeContent(AMQMessage message) throws AMQException; +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/exchange/NoRouteException.java b/java/broker/src/main/java/org/apache/qpid/server/exchange/NoRouteException.java new file mode 100644 index 0000000000..fb0a330263 --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/exchange/NoRouteException.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.server.exchange; + +import org.apache.qpid.server.RequiredDeliveryException; +import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.protocol.AMQConstant; + +/** + * Thrown by an exchange if there is no way to route a message with the + * mandatory flag set. + */ +public class NoRouteException extends RequiredDeliveryException +{ + public NoRouteException(String msg, AMQMessage message) + { + super(msg, message); + } + + public int getReplyCode() + { + return AMQConstant.NO_ROUTE.getCode(); + } +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/handler/BasicAckMethodHandler.java b/java/broker/src/main/java/org/apache/qpid/server/handler/BasicAckMethodHandler.java new file mode 100644 index 0000000000..b2b7a21296 --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/handler/BasicAckMethodHandler.java @@ -0,0 +1,55 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.handler; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.BasicAckBody; +import org.apache.qpid.server.exchange.ExchangeRegistry; +import org.apache.qpid.server.protocol.AMQMethodEvent; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.queue.QueueRegistry; +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.server.state.StateAwareMethodListener; +import org.apache.qpid.server.AMQChannel; + +public class BasicAckMethodHandler implements StateAwareMethodListener +{ + private static final BasicAckMethodHandler _instance = new BasicAckMethodHandler(); + + public static BasicAckMethodHandler getInstance() + { + return _instance; + } + + private BasicAckMethodHandler() + { + } + + public void methodReceived(AMQStateManager stateManager, QueueRegistry queueRegistry, + ExchangeRegistry exchangeRegistry, AMQProtocolSession protocolSession, + AMQMethodEvent evt) throws AMQException + { + BasicAckBody body = evt.getMethod(); + final AMQChannel channel = protocolSession.getChannel(evt.getChannelId()); + // this method throws an AMQException if the delivery tag is not known + channel.acknowledgeMessage(body.deliveryTag, body.multiple); + } +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/handler/BasicCancelMethodHandler.java b/java/broker/src/main/java/org/apache/qpid/server/handler/BasicCancelMethodHandler.java new file mode 100644 index 0000000000..673556cbec --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/handler/BasicCancelMethodHandler.java @@ -0,0 +1,61 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.handler; + +import org.apache.qpid.framing.AMQFrame; +import org.apache.qpid.framing.BasicCancelBody; +import org.apache.qpid.framing.BasicCancelOkBody; +import org.apache.qpid.server.state.StateAwareMethodListener; +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.server.queue.QueueRegistry; +import org.apache.qpid.server.exchange.ExchangeRegistry; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.protocol.AMQMethodEvent; +import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.AMQException; + +public class BasicCancelMethodHandler implements StateAwareMethodListener +{ + private static final BasicCancelMethodHandler _instance = new BasicCancelMethodHandler(); + + public static BasicCancelMethodHandler getInstance() + { + return _instance; + } + + private BasicCancelMethodHandler() + { + } + + public void methodReceived(AMQStateManager stateManager, QueueRegistry queueRegistry, + ExchangeRegistry exchangeRegistry, AMQProtocolSession protocolSession, + AMQMethodEvent evt) throws AMQException + { + final AMQChannel channel = protocolSession.getChannel(evt.getChannelId()); + final BasicCancelBody body = evt.getMethod(); + channel.unsubscribeConsumer(protocolSession, body.consumerTag); + if(!body.nowait) + { + final AMQFrame responseFrame = BasicCancelOkBody.createAMQFrame(evt.getChannelId(), body.consumerTag); + protocolSession.writeFrame(responseFrame); + } + } +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java b/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java new file mode 100644 index 0000000000..d4c94061a0 --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java @@ -0,0 +1,93 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.handler; + +import org.apache.qpid.AMQException; +import org.apache.qpid.protocol.AMQConstant; +import org.apache.qpid.framing.BasicConsumeBody; +import org.apache.qpid.framing.BasicConsumeOkBody; +import org.apache.qpid.framing.ConnectionCloseBody; +import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.ConsumerTagNotUniqueException; +import org.apache.qpid.server.exchange.ExchangeRegistry; +import org.apache.qpid.server.protocol.AMQMethodEvent; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.queue.QueueRegistry; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.server.state.StateAwareMethodListener; +import org.apache.log4j.Logger; + +public class BasicConsumeMethodHandler implements StateAwareMethodListener +{ + private static final Logger _log = Logger.getLogger(BasicConsumeMethodHandler.class); + + private static final BasicConsumeMethodHandler _instance = new BasicConsumeMethodHandler(); + + public static BasicConsumeMethodHandler getInstance() + { + return _instance; + } + + private BasicConsumeMethodHandler() + { + } + + public void methodReceived(AMQStateManager stateManager, QueueRegistry queueRegistry, + ExchangeRegistry exchangeRegistry, AMQProtocolSession session, + AMQMethodEvent evt) throws AMQException + { + BasicConsumeBody body = evt.getMethod(); + final int channelId = evt.getChannelId(); + + AMQChannel channel = session.getChannel(channelId); + if (channel == null) + { + _log.error("Channel " + channelId + " not found"); + // TODO: either alert or error that the + } + else + { + AMQQueue queue = body.queue == null ? channel.getDefaultQueue() : queueRegistry.getQueue(body.queue); + + if(queue == null) + { + _log.info("No queue for '" + body.queue + "'"); + } + try + { + String consumerTag = channel.subscribeToQueue(body.consumerTag, queue, session, !body.noAck); + if(!body.nowait) + { + session.writeFrame(BasicConsumeOkBody.createAMQFrame(channelId, consumerTag)); + } + + //now allow queue to start async processing of any backlog of messages + queue.deliverAsync(); + } + catch(ConsumerTagNotUniqueException e) + { + String msg = "Non-unique consumer tag, '" + body.consumerTag + "'"; + session.writeFrame(ConnectionCloseBody.createAMQFrame(channelId, AMQConstant.NOT_ALLOWED.getCode(), msg, BasicConsumeBody.CLASS_ID, BasicConsumeBody.METHOD_ID)); + } + } + } +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/handler/BasicPublishMethodHandler.java b/java/broker/src/main/java/org/apache/qpid/server/handler/BasicPublishMethodHandler.java new file mode 100644 index 0000000000..efdbe7aae4 --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/handler/BasicPublishMethodHandler.java @@ -0,0 +1,80 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.handler; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQFrame; +import org.apache.qpid.framing.BasicPublishBody; +import org.apache.qpid.framing.ChannelCloseBody; +import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.exchange.ExchangeRegistry; +import org.apache.qpid.server.protocol.AMQMethodEvent; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.queue.QueueRegistry; +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.server.state.StateAwareMethodListener; + +public class BasicPublishMethodHandler implements StateAwareMethodListener +{ + private static final BasicPublishMethodHandler _instance = new BasicPublishMethodHandler(); + + public static BasicPublishMethodHandler getInstance() + { + return _instance; + } + + private BasicPublishMethodHandler() + { + } + + public void methodReceived(AMQStateManager stateManager, QueueRegistry queueRegistry, + ExchangeRegistry exchangeRegistry, AMQProtocolSession protocolSession, + AMQMethodEvent evt) throws AMQException + { + final BasicPublishBody body = evt.getMethod(); + + // TODO: check the delivery tag field details - is it unique across the broker or per subscriber? + if (body.exchange == null) + { + body.exchange = "amq.direct"; + } + Exchange e = exchangeRegistry.getExchange(body.exchange); + // if the exchange does not exist we raise a channel exception + if (e == null) + { + protocolSession.closeChannel(evt.getChannelId()); + // TODO: modify code gen to make getClazz and getMethod public methods rather than protected + // then we can remove the hardcoded 0,0 + AMQFrame cf = ChannelCloseBody.createAMQFrame(evt.getChannelId(), 500, "Unknown exchange name", 0, 0); + protocolSession.writeFrame(cf); + } + else + { + // The partially populated BasicDeliver frame plus the received route body + // is stored in the channel. Once the final body frame has been received + // it is routed to the exchange. + AMQChannel channel = protocolSession.getChannel(evt.getChannelId()); + channel.setPublishFrame(body, protocolSession); + } + } +} + diff --git a/java/broker/src/main/java/org/apache/qpid/server/handler/BasicQosHandler.java b/java/broker/src/main/java/org/apache/qpid/server/handler/BasicQosHandler.java new file mode 100644 index 0000000000..1357ff16b9 --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/handler/BasicQosHandler.java @@ -0,0 +1,49 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.handler; + +import org.apache.qpid.framing.AMQFrame; +import org.apache.qpid.framing.BasicQosBody; +import org.apache.qpid.framing.BasicQosOkBody; +import org.apache.qpid.server.state.StateAwareMethodListener; +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.server.queue.QueueRegistry; +import org.apache.qpid.server.exchange.ExchangeRegistry; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.protocol.AMQMethodEvent; +import org.apache.qpid.AMQException; + +public class BasicQosHandler implements StateAwareMethodListener +{ + private static final BasicQosHandler _instance = new BasicQosHandler(); + + public static BasicQosHandler getInstance() + { + return _instance; + } + + public void methodReceived(AMQStateManager stateMgr, QueueRegistry queues, ExchangeRegistry exchanges, + AMQProtocolSession session, AMQMethodEvent evt) throws AMQException + { + session.getChannel(evt.getChannelId()).setPrefetchCount(evt.getMethod().prefetchCount); + session.writeFrame(new AMQFrame(evt.getChannelId(), new BasicQosOkBody())); + } +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRecoverMethodHandler.java b/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRecoverMethodHandler.java new file mode 100644 index 0000000000..85e802d10d --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRecoverMethodHandler.java @@ -0,0 +1,57 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.handler; + +import org.apache.qpid.server.state.StateAwareMethodListener; +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.server.queue.QueueRegistry; +import org.apache.qpid.server.exchange.ExchangeRegistry; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.protocol.AMQMethodEvent; +import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.framing.BasicRecoverBody; +import org.apache.qpid.AMQException; +import org.apache.log4j.Logger; + +public class BasicRecoverMethodHandler implements StateAwareMethodListener +{ + private static final Logger _logger = Logger.getLogger(BasicRecoverMethodHandler.class); + + private static final BasicRecoverMethodHandler _instance = new BasicRecoverMethodHandler(); + + public static BasicRecoverMethodHandler getInstance() + { + return _instance; + } + + public void methodReceived(AMQStateManager stateManager, QueueRegistry queueRegistry, + ExchangeRegistry exchangeRegistry, AMQProtocolSession protocolSession, + AMQMethodEvent evt) throws AMQException + { + _logger.debug("Recover received on protocol session " + protocolSession + " and channel " + evt.getChannelId()); + AMQChannel channel = protocolSession.getChannel(evt.getChannelId()); + if (channel == null) + { + throw new AMQException("Unknown channel " + evt.getChannelId()); + } + channel.resend(protocolSession); + } +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelCloseHandler.java b/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelCloseHandler.java new file mode 100644 index 0000000000..0efe12b137 --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelCloseHandler.java @@ -0,0 +1,61 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.handler; + +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.ChannelCloseBody; +import org.apache.qpid.framing.AMQFrame; +import org.apache.qpid.framing.ChannelCloseOkBody; +import org.apache.qpid.server.exchange.ExchangeRegistry; +import org.apache.qpid.server.protocol.AMQMethodEvent; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.queue.QueueRegistry; +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.server.state.StateAwareMethodListener; + +public class ChannelCloseHandler implements StateAwareMethodListener +{ + private static final Logger _logger = Logger.getLogger(ChannelCloseHandler.class); + + private static ChannelCloseHandler _instance = new ChannelCloseHandler(); + + public static ChannelCloseHandler getInstance() + { + return _instance; + } + + private ChannelCloseHandler() + { + } + + public void methodReceived(AMQStateManager stateManager, QueueRegistry queueRegistry, + ExchangeRegistry exchangeRegistry, AMQProtocolSession protocolSession, + AMQMethodEvent evt) throws AMQException + { + ChannelCloseBody body = evt.getMethod(); + _logger.info("Received channel close for id " + evt.getChannelId() + " citing class " + body.classId + + " and method " + body.methodId); + protocolSession.closeChannel(evt.getChannelId()); + AMQFrame response = ChannelCloseOkBody.createAMQFrame(evt.getChannelId()); + protocolSession.writeFrame(response); + } +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelCloseOkHandler.java b/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelCloseOkHandler.java new file mode 100644 index 0000000000..fd6714de3a --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelCloseOkHandler.java @@ -0,0 +1,54 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.handler; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.ChannelCloseOkBody; +import org.apache.qpid.server.exchange.ExchangeRegistry; +import org.apache.qpid.server.protocol.AMQMethodEvent; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.queue.QueueRegistry; +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.server.state.StateAwareMethodListener; +import org.apache.log4j.Logger; + +public class ChannelCloseOkHandler implements StateAwareMethodListener +{ + private static final Logger _logger = Logger.getLogger(ChannelCloseOkHandler.class); + + private static ChannelCloseOkHandler _instance = new ChannelCloseOkHandler(); + + public static ChannelCloseOkHandler getInstance() + { + return _instance; + } + + private ChannelCloseOkHandler() + { + } + + public void methodReceived(AMQStateManager stateManager, QueueRegistry queueRegistry, + ExchangeRegistry exchangeRegistry, AMQProtocolSession protocolSession, + AMQMethodEvent evt) throws AMQException + { + _logger.info("Received channel-close-ok for channel-id " + evt.getChannelId()); + } +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelFlowHandler.java b/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelFlowHandler.java new file mode 100644 index 0000000000..8417ada15f --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelFlowHandler.java @@ -0,0 +1,64 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.handler; + +import org.apache.log4j.Logger; +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.server.state.StateAwareMethodListener; +import org.apache.qpid.server.queue.QueueRegistry; +import org.apache.qpid.server.exchange.ExchangeRegistry; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.protocol.AMQMethodEvent; +import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.framing.AMQFrame; +import org.apache.qpid.framing.ChannelFlowBody; +import org.apache.qpid.framing.ChannelFlowOkBody; +import org.apache.qpid.framing.ChannelCloseBody; +import org.apache.qpid.AMQException; + +public class ChannelFlowHandler implements StateAwareMethodListener +{ + private static final Logger _logger = Logger.getLogger(ChannelFlowHandler.class); + + private static ChannelFlowHandler _instance = new ChannelFlowHandler(); + + public static ChannelFlowHandler getInstance() + { + return _instance; + } + + private ChannelFlowHandler() + { + } + + public void methodReceived(AMQStateManager stateManager, QueueRegistry queueRegistry, + ExchangeRegistry exchangeRegistry, AMQProtocolSession protocolSession, + AMQMethodEvent evt) throws AMQException + { + ChannelFlowBody body = evt.getMethod(); + + AMQChannel channel = protocolSession.getChannel(evt.getChannelId()); + channel.setSuspended(!body.active); + _logger.debug("Channel.Flow for channel " + evt.getChannelId() + ", active=" + body.active); + + AMQFrame response = ChannelFlowOkBody.createAMQFrame(evt.getChannelId(), body.active); + protocolSession.writeFrame(response); + }} diff --git a/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelOpenHandler.java b/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelOpenHandler.java new file mode 100644 index 0000000000..4cccc774ba --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelOpenHandler.java @@ -0,0 +1,61 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.handler; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQFrame; +import org.apache.qpid.framing.ChannelOpenBody; +import org.apache.qpid.framing.ChannelOpenOkBody; +import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.registry.IApplicationRegistry; +import org.apache.qpid.server.exchange.ExchangeRegistry; +import org.apache.qpid.server.protocol.AMQMethodEvent; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.queue.QueueRegistry; +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.server.state.StateAwareMethodListener; + +public class ChannelOpenHandler implements StateAwareMethodListener +{ + private static ChannelOpenHandler _instance = new ChannelOpenHandler(); + + public static ChannelOpenHandler getInstance() + { + return _instance; + } + + private ChannelOpenHandler() + { + } + + public void methodReceived(AMQStateManager stateManager, QueueRegistry queueRegistry, + ExchangeRegistry exchangeRegistry, AMQProtocolSession protocolSession, + AMQMethodEvent evt) throws AMQException + { + IApplicationRegistry registry = ApplicationRegistry.getInstance(); + final AMQChannel channel = new AMQChannel(evt.getChannelId(), registry.getMessageStore(), + exchangeRegistry); + protocolSession.addChannel(channel); + AMQFrame response = ChannelOpenOkBody.createAMQFrame(evt.getChannelId()); + protocolSession.writeFrame(response); + } +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionCloseMethodHandler.java b/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionCloseMethodHandler.java new file mode 100644 index 0000000000..7bdb1942d0 --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionCloseMethodHandler.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.server.handler; + +import org.apache.qpid.framing.ConnectionCloseBody; +import org.apache.qpid.framing.AMQFrame; +import org.apache.qpid.framing.ConnectionCloseOkBody; +import org.apache.qpid.server.state.StateAwareMethodListener; +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.server.queue.QueueRegistry; +import org.apache.qpid.server.exchange.ExchangeRegistry; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.protocol.AMQMethodEvent; +import org.apache.qpid.AMQException; +import org.apache.log4j.Logger; + +public class ConnectionCloseMethodHandler implements StateAwareMethodListener +{ + private static final Logger _logger = Logger.getLogger(ConnectionCloseMethodHandler.class); + + private static ConnectionCloseMethodHandler _instance = new ConnectionCloseMethodHandler(); + + public static ConnectionCloseMethodHandler getInstance() + { + return _instance; + } + + private ConnectionCloseMethodHandler() + { + } + + public void methodReceived(AMQStateManager stateManager, QueueRegistry queueRegistry, + ExchangeRegistry exchangeRegistry, AMQProtocolSession protocolSession, + AMQMethodEvent evt) throws AMQException + { + final ConnectionCloseBody body = evt.getMethod(); + _logger.info("ConnectionClose received with reply code/reply text " + body.replyCode + "/" + + body.replyText + " for " + protocolSession); + try + { + protocolSession.closeSession(); + } + catch (Exception e) + { + _logger.error("Error closing protocol session: " + e, e); + } + final AMQFrame response = ConnectionCloseOkBody.createAMQFrame(evt.getChannelId()); + protocolSession.writeFrame(response); + } +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionCloseOkMethodHandler.java b/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionCloseOkMethodHandler.java new file mode 100644 index 0000000000..cc9277593b --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionCloseOkMethodHandler.java @@ -0,0 +1,66 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.handler; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.ConnectionCloseOkBody; +import org.apache.qpid.server.exchange.ExchangeRegistry; +import org.apache.qpid.server.protocol.AMQMethodEvent; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.queue.QueueRegistry; +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.server.state.StateAwareMethodListener; +import org.apache.qpid.server.state.AMQState; +import org.apache.log4j.Logger; + +public class ConnectionCloseOkMethodHandler implements StateAwareMethodListener +{ + private static final Logger _logger = Logger.getLogger(ConnectionCloseOkMethodHandler.class); + + private static ConnectionCloseOkMethodHandler _instance = new ConnectionCloseOkMethodHandler(); + + public static ConnectionCloseOkMethodHandler getInstance() + { + return _instance; + } + + private ConnectionCloseOkMethodHandler() + { + } + + public void methodReceived(AMQStateManager stateManager, QueueRegistry queueRegistry, + ExchangeRegistry exchangeRegistry, AMQProtocolSession protocolSession, + AMQMethodEvent evt) throws AMQException + { + //todo should this not do more than just log the method? + _logger.info("Received Connection-close-ok"); + + try + { + stateManager.changeState(AMQState.CONNECTION_CLOSED); + protocolSession.closeSession(); + } + catch (Exception e) + { + _logger.error("Error closing protocol session: " + e, e); + } + } +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionOpenMethodHandler.java b/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionOpenMethodHandler.java new file mode 100644 index 0000000000..bfcc50e1f8 --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionOpenMethodHandler.java @@ -0,0 +1,71 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.handler; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQFrame; +import org.apache.qpid.framing.ConnectionOpenBody; +import org.apache.qpid.framing.ConnectionOpenOkBody; +import org.apache.qpid.server.exchange.ExchangeRegistry; +import org.apache.qpid.server.protocol.AMQMethodEvent; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.queue.QueueRegistry; +import org.apache.qpid.server.state.AMQState; +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.server.state.StateAwareMethodListener; + +public class ConnectionOpenMethodHandler implements StateAwareMethodListener +{ + private static ConnectionOpenMethodHandler _instance = new ConnectionOpenMethodHandler(); + + public static ConnectionOpenMethodHandler getInstance() + { + return _instance; + } + + private ConnectionOpenMethodHandler() + { + } + + private static String generateClientID() + { + return Long.toString(System.currentTimeMillis()); + } + + public void methodReceived(AMQStateManager stateManager, QueueRegistry queueRegistry, + ExchangeRegistry exchangeRegistry, AMQProtocolSession protocolSession, + AMQMethodEvent evt) throws AMQException + { + ConnectionOpenBody body = evt.getMethod(); + String contextKey = body.virtualHost; + + //todo //FIXME The virtual host must be validated by the server for the connection to open-ok + // See Spec (0.8.2). Section 3.1.2 Virtual Hosts + if (contextKey == null) + { + contextKey = generateClientID(); + } + protocolSession.setContextKey(contextKey); + AMQFrame response = ConnectionOpenOkBody.createAMQFrame((short)0, contextKey); + stateManager.changeState(AMQState.CONNECTION_OPEN); + protocolSession.writeFrame(response); + } +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionSecureOkMethodHandler.java b/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionSecureOkMethodHandler.java new file mode 100644 index 0000000000..c858d25e2d --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionSecureOkMethodHandler.java @@ -0,0 +1,118 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.handler; + +import org.apache.qpid.AMQException; +import org.apache.qpid.AMQChannelException; +import org.apache.qpid.protocol.AMQConstant; +import org.apache.qpid.framing.*; +import org.apache.qpid.server.exchange.ExchangeRegistry; +import org.apache.qpid.server.protocol.AMQMethodEvent; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.protocol.HeartbeatConfig; +import org.apache.qpid.server.queue.QueueRegistry; +import org.apache.qpid.server.state.AMQState; +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.server.state.StateAwareMethodListener; +import org.apache.qpid.server.security.auth.AuthenticationManager; +import org.apache.qpid.server.security.auth.AuthenticationResult; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.log4j.Logger; + +import javax.security.sasl.SaslServer; +import javax.security.sasl.SaslException; + +public class ConnectionSecureOkMethodHandler implements StateAwareMethodListener +{ + private static final Logger _logger = Logger.getLogger(ConnectionSecureOkMethodHandler.class); + + private static ConnectionSecureOkMethodHandler _instance = new ConnectionSecureOkMethodHandler(); + + public static ConnectionSecureOkMethodHandler getInstance() + { + return _instance; + } + + private ConnectionSecureOkMethodHandler() + { + } + + public void methodReceived(AMQStateManager stateManager, QueueRegistry queueRegistry, + ExchangeRegistry exchangeRegistry, AMQProtocolSession protocolSession, + AMQMethodEvent evt) throws AMQException + { + ConnectionSecureOkBody body = evt.getMethod(); + + AuthenticationManager authMgr = ApplicationRegistry.getInstance().getAuthenticationManager(); + SaslServer ss = protocolSession.getSaslServer(); + if (ss == null) + { + throw new AMQException("No SASL context set up in session"); + } + + AuthenticationResult authResult = authMgr.authenticate(ss, body.response); + switch (authResult.status) + { + case ERROR: + // Can't do this as we violate protocol. Need to send Close + // throw new AMQException(AMQConstant.NOT_ALLOWED.getCode(), AMQConstant.NOT_ALLOWED.getName()); + _logger.info("Authentication failed"); + stateManager.changeState(AMQState.CONNECTION_CLOSING); + AMQFrame close = ConnectionCloseBody.createAMQFrame(0, AMQConstant.NOT_ALLOWED.getCode(), + AMQConstant.NOT_ALLOWED.getName(), + ConnectionCloseBody.CLASS_ID, + ConnectionCloseBody.METHOD_ID); + protocolSession.writeFrame(close); + disposeSaslServer(protocolSession); + break; + case SUCCESS: + _logger.info("Connected as: " + ss.getAuthorizationID()); + stateManager.changeState(AMQState.CONNECTION_NOT_TUNED); + AMQFrame tune = ConnectionTuneBody.createAMQFrame(0, Integer.MAX_VALUE, + ConnectionStartOkMethodHandler.getConfiguredFrameSize(), + HeartbeatConfig.getInstance().getDelay()); + protocolSession.writeFrame(tune); + disposeSaslServer(protocolSession); + break; + case CONTINUE: + stateManager.changeState(AMQState.CONNECTION_NOT_AUTH); + AMQFrame challenge = ConnectionSecureBody.createAMQFrame(0, authResult.challenge); + protocolSession.writeFrame(challenge); + } + } + + private void disposeSaslServer(AMQProtocolSession ps) + { + SaslServer ss = ps.getSaslServer(); + if (ss != null) + { + ps.setSaslServer(null); + try + { + ss.dispose(); + } + catch (SaslException e) + { + _logger.error("Error disposing of Sasl server: " + e); + } + } + } +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionStartOkMethodHandler.java b/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionStartOkMethodHandler.java new file mode 100644 index 0000000000..00ae547683 --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionStartOkMethodHandler.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.server.handler; + +import org.apache.log4j.Logger; +import org.apache.commons.configuration.Configuration; +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQFrame; +import org.apache.qpid.framing.ConnectionSecureBody; +import org.apache.qpid.framing.ConnectionStartOkBody; +import org.apache.qpid.framing.ConnectionTuneBody; +import org.apache.qpid.server.exchange.ExchangeRegistry; +import org.apache.qpid.server.protocol.AMQMethodEvent; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.protocol.HeartbeatConfig; +import org.apache.qpid.server.queue.QueueRegistry; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.security.auth.AuthenticationManager; +import org.apache.qpid.server.security.auth.AuthenticationResult; +import org.apache.qpid.server.state.AMQState; +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.server.state.StateAwareMethodListener; + +import javax.security.sasl.SaslException; +import javax.security.sasl.SaslServer; + + +public class ConnectionStartOkMethodHandler implements StateAwareMethodListener +{ + private static final Logger _logger = Logger.getLogger(ConnectionStartOkMethodHandler.class); + + private static ConnectionStartOkMethodHandler _instance = new ConnectionStartOkMethodHandler(); + + private static final int DEFAULT_FRAME_SIZE = 65536; + + public static StateAwareMethodListener getInstance() + { + return _instance; + } + + private ConnectionStartOkMethodHandler() + { + } + + public void methodReceived(AMQStateManager stateManager, QueueRegistry queueRegistry, + ExchangeRegistry exchangeRegistry, AMQProtocolSession protocolSession, + AMQMethodEvent evt) throws AMQException + { + final ConnectionStartOkBody body = evt.getMethod(); + _logger.info("SASL Mechanism selected: " + body.mechanism); + _logger.info("Locale selected: " + body.locale); + + AuthenticationManager authMgr = ApplicationRegistry.getInstance().getAuthenticationManager(); + + SaslServer ss = null; + try + { + ss = authMgr.createSaslServer(body.mechanism, protocolSession.getLocalFQDN()); + protocolSession.setSaslServer(ss); + + AuthenticationResult authResult = authMgr.authenticate(ss, body.response); + + switch (authResult.status) + { + case ERROR: + throw new AMQException("Authentication failed"); + case SUCCESS: + _logger.info("Connected as: " + ss.getAuthorizationID()); + stateManager.changeState(AMQState.CONNECTION_NOT_TUNED); + AMQFrame tune = ConnectionTuneBody.createAMQFrame(0, Integer.MAX_VALUE, getConfiguredFrameSize(), + HeartbeatConfig.getInstance().getDelay()); + protocolSession.writeFrame(tune); + break; + case CONTINUE: + stateManager.changeState(AMQState.CONNECTION_NOT_AUTH); + AMQFrame challenge = ConnectionSecureBody.createAMQFrame(0, authResult.challenge); + protocolSession.writeFrame(challenge); + } + } + catch (SaslException e) + { + disposeSaslServer(protocolSession); + throw new AMQException("SASL error: " + e, e); + } + } + + private void disposeSaslServer(AMQProtocolSession ps) + { + SaslServer ss = ps.getSaslServer(); + if (ss != null) + { + ps.setSaslServer(null); + try + { + ss.dispose(); + } + catch (SaslException e) + { + _logger.error("Error disposing of Sasl server: " + e); + } + } + } + + static int getConfiguredFrameSize() + { + final Configuration config = ApplicationRegistry.getInstance().getConfiguration(); + final int framesize = config.getInt("advanced.framesize", DEFAULT_FRAME_SIZE); + _logger.info("Framesize set to " + framesize); + return framesize; + } +} + diff --git a/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionTuneOkMethodHandler.java b/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionTuneOkMethodHandler.java new file mode 100644 index 0000000000..f0b4e0a515 --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionTuneOkMethodHandler.java @@ -0,0 +1,57 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.handler; + +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.ConnectionTuneOkBody; +import org.apache.qpid.server.exchange.ExchangeRegistry; +import org.apache.qpid.server.protocol.AMQMethodEvent; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.queue.QueueRegistry; +import org.apache.qpid.server.state.AMQState; +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.server.state.StateAwareMethodListener; + +public class ConnectionTuneOkMethodHandler implements StateAwareMethodListener +{ + private static final Logger _logger = Logger.getLogger(ConnectionTuneOkMethodHandler.class); + + private static ConnectionTuneOkMethodHandler _instance = new ConnectionTuneOkMethodHandler(); + + public static ConnectionTuneOkMethodHandler getInstance() + { + return _instance; + } + + public void methodReceived(AMQStateManager stateManager, QueueRegistry queueRegistry, + ExchangeRegistry exchangeRegistry, AMQProtocolSession protocolSession, + AMQMethodEvent evt) throws AMQException + { + ConnectionTuneOkBody body = evt.getMethod(); + if (_logger.isDebugEnabled()) + { + _logger.debug(body); + } + stateManager.changeState(AMQState.CONNECTION_NOT_OPENED); + protocolSession.initHeartbeats(body.heartbeat); + } +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeclareHandler.java b/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeclareHandler.java new file mode 100644 index 0000000000..b7c75e290a --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeclareHandler.java @@ -0,0 +1,82 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.handler; + +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQFrame; +import org.apache.qpid.framing.ExchangeDeclareBody; +import org.apache.qpid.framing.ExchangeDeclareOkBody; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.exchange.ExchangeRegistry; +import org.apache.qpid.server.exchange.ExchangeFactory; +import org.apache.qpid.server.protocol.AMQMethodEvent; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.queue.QueueRegistry; +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.server.state.StateAwareMethodListener; +import org.apache.qpid.server.registry.ApplicationRegistry; + +public class ExchangeDeclareHandler implements StateAwareMethodListener +{ + private static final Logger _logger = Logger.getLogger(ExchangeDeclareHandler.class); + + private static final ExchangeDeclareHandler _instance = new ExchangeDeclareHandler(); + + public static ExchangeDeclareHandler getInstance() + { + return _instance; + } + + private final ExchangeFactory exchangeFactory; + + private ExchangeDeclareHandler() + { + exchangeFactory = ApplicationRegistry.getInstance().getExchangeFactory(); + } + + public void methodReceived(AMQStateManager stateManager, QueueRegistry queueRegistry, + ExchangeRegistry exchangeRegistry, AMQProtocolSession protocolSession, + AMQMethodEvent evt) throws AMQException + { + final ExchangeDeclareBody body = evt.getMethod(); + if (_logger.isDebugEnabled()) + { + _logger.debug("Request to declare exchange of type " + body.type + " with name " + body.exchange); + } + synchronized(exchangeRegistry) + { + Exchange exchange = exchangeRegistry.getExchange(body.exchange); + + if (exchange == null) + { + exchange = exchangeFactory.createExchange(body.exchange, body.type, body.durable, + body.passive, body.ticket); + exchangeRegistry.registerExchange(exchange); + } + } + if(!body.nowait) + { + AMQFrame response = ExchangeDeclareOkBody.createAMQFrame(evt.getChannelId()); + protocolSession.writeFrame(response); + } + } +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeleteHandler.java b/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeleteHandler.java new file mode 100644 index 0000000000..93ef902190 --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeleteHandler.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.server.handler; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQFrame; +import org.apache.qpid.framing.ExchangeDeleteBody; +import org.apache.qpid.framing.ExchangeDeleteOkBody; +import org.apache.qpid.server.exchange.ExchangeInUseException; +import org.apache.qpid.server.exchange.ExchangeRegistry; +import org.apache.qpid.server.protocol.AMQMethodEvent; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.queue.QueueRegistry; +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.server.state.StateAwareMethodListener; + +public class ExchangeDeleteHandler implements StateAwareMethodListener +{ + private static final ExchangeDeleteHandler _instance = new ExchangeDeleteHandler(); + + public static ExchangeDeleteHandler getInstance() + { + return _instance; + } + + private ExchangeDeleteHandler() + { + } + + public void methodReceived(AMQStateManager stateManager, QueueRegistry queueRegistry, + ExchangeRegistry exchangeRegistry, AMQProtocolSession protocolSession, + AMQMethodEvent evt) throws AMQException + { + ExchangeDeleteBody body = evt.getMethod(); + try + { + exchangeRegistry.unregisterExchange(body.exchange, body.ifUnused); + AMQFrame response = ExchangeDeleteOkBody.createAMQFrame(evt.getChannelId()); + protocolSession.writeFrame(response); + } + catch (ExchangeInUseException e) + { + // TODO: sort out consistent channel close mechanism that does all clean up etc. + } + + } +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/handler/OnCurrentThreadExecutor.java b/java/broker/src/main/java/org/apache/qpid/server/handler/OnCurrentThreadExecutor.java new file mode 100644 index 0000000000..ac516b6133 --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/handler/OnCurrentThreadExecutor.java @@ -0,0 +1,34 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.handler; + +import java.util.concurrent.Executor; + +/** + * An executor that executes the task on the current thread. + */ +public class OnCurrentThreadExecutor implements Executor +{ + public void execute(Runnable command) + { + command.run(); + } +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/handler/QueueBindHandler.java b/java/broker/src/main/java/org/apache/qpid/server/handler/QueueBindHandler.java new file mode 100644 index 0000000000..cf9e40a660 --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/handler/QueueBindHandler.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.server.handler; + +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.protocol.AMQConstant; +import org.apache.qpid.framing.AMQFrame; +import org.apache.qpid.framing.QueueBindBody; +import org.apache.qpid.framing.QueueBindOkBody; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.exchange.ExchangeRegistry; +import org.apache.qpid.server.protocol.AMQMethodEvent; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.queue.QueueRegistry; +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.server.state.StateAwareMethodListener; + +public class QueueBindHandler implements StateAwareMethodListener +{ + private static final Logger _log = Logger.getLogger(QueueBindHandler.class); + + private static final QueueBindHandler _instance = new QueueBindHandler(); + + public static QueueBindHandler getInstance() + { + return _instance; + } + + private QueueBindHandler() + { + } + + public void methodReceived(AMQStateManager stateManager, QueueRegistry queueRegistry, + ExchangeRegistry exchangeRegistry, AMQProtocolSession protocolSession, + AMQMethodEvent evt) throws AMQException + { + final QueueBindBody body = evt.getMethod(); + final AMQQueue queue; + if (body.queue == null) + { + queue = protocolSession.getChannel(evt.getChannelId()).getDefaultQueue(); + if (queue == null) + { + throw new AMQException("No default queue defined on channel and queue was null"); + } + if (body.routingKey == null) + { + body.routingKey = queue.getName(); + } + } + else + { + queue = queueRegistry.getQueue(body.queue); + } + + if (queue == null) + { + throw body.getChannelException(AMQConstant.NOT_FOUND.getCode(), "Queue " + body.queue + " does not exist."); + } + final Exchange exch = exchangeRegistry.getExchange(body.exchange); + if (exch == null) + { + throw body.getChannelException(AMQConstant.NOT_FOUND.getCode(), "Exchange " + body.exchange + " does not exist."); + } + exch.registerQueue(body.routingKey, queue, body.arguments); + queue.bind(body.routingKey, exch); + if (_log.isInfoEnabled()) + { + _log.info("Binding queue " + queue + " to exchange " + exch + " with routing key " + body.routingKey); + } + if (!body.nowait) + { + final AMQFrame response = QueueBindOkBody.createAMQFrame(evt.getChannelId()); + protocolSession.writeFrame(response); + } + } +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java b/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java new file mode 100644 index 0000000000..b7004de2a9 --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java @@ -0,0 +1,127 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.handler; + +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.configuration.Configured; +import org.apache.qpid.framing.AMQFrame; +import org.apache.qpid.framing.QueueDeclareBody; +import org.apache.qpid.framing.QueueDeclareOkBody; +import org.apache.qpid.server.exchange.ExchangeRegistry; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.protocol.AMQMethodEvent; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.queue.QueueRegistry; +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.server.state.StateAwareMethodListener; +import org.apache.qpid.server.configuration.Configurator; +import org.apache.qpid.server.store.MessageStore; +import org.apache.qpid.server.registry.ApplicationRegistry; + +import java.text.MessageFormat; +import java.util.concurrent.atomic.AtomicInteger; + +public class QueueDeclareHandler implements StateAwareMethodListener +{ + private static final Logger _log = Logger.getLogger(QueueDeclareHandler.class); + + private static final QueueDeclareHandler _instance = new QueueDeclareHandler(); + + public static QueueDeclareHandler getInstance() + { + return _instance; + } + + @Configured(path = "queue.auto_register", defaultValue = "false") + public boolean autoRegister; + + private final AtomicInteger _counter = new AtomicInteger(); + + private final MessageStore _store; + + protected QueueDeclareHandler() + { + Configurator.configure(this); + _store = ApplicationRegistry.getInstance().getMessageStore(); + } + + public void methodReceived(AMQStateManager stateManager, QueueRegistry queueRegistry, + ExchangeRegistry exchangeRegistry, AMQProtocolSession protocolSession, + AMQMethodEvent evt) throws AMQException + { + QueueDeclareBody body = evt.getMethod(); + + // if we aren't given a queue name, we create one which we return to the client + if (body.queue == null) + { + body.queue = createName(); + } + //TODO: do we need to check that the queue already exists with exactly the same "configuration"? + + synchronized (queueRegistry) + { + AMQQueue queue; + if ((queue = queueRegistry.getQueue(body.queue)) == null) + { + queue = createQueue(body, queueRegistry, protocolSession); + if (queue.isDurable() && !queue.isAutoDelete()) + { + _store.createQueue(queue); + } + queueRegistry.registerQueue(queue); + if (autoRegister) + { + Exchange defaultExchange = exchangeRegistry.getExchange("amq.direct"); + defaultExchange.registerQueue(body.queue, queue, null); + queue.bind(body.queue, defaultExchange); + _log.info("Queue " + body.queue + " bound to default exchange"); + } + } + //set this as the default queue on the channel: + protocolSession.getChannel(evt.getChannelId()).setDefaultQueue(queue); + } + if (!body.nowait) + { + AMQFrame response = QueueDeclareOkBody.createAMQFrame(evt.getChannelId(), body.queue, 0L, 0L); + _log.info("Queue " + body.queue + " declared successfully"); + protocolSession.writeFrame(response); + } + } + + protected String createName() + { + return "tmp_" + pad(_counter.incrementAndGet()); + } + + protected static String pad(int value) + { + return MessageFormat.format("{0,number,0000000000000}", value); + } + + protected AMQQueue createQueue(QueueDeclareBody body, QueueRegistry registry, AMQProtocolSession session) + throws AMQException + { + String owner = body.exclusive ? session.getContextKey() : null; + return new AMQQueue(body.queue, body.durable, owner, body.autoDelete, registry); + } +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeleteHandler.java b/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeleteHandler.java new file mode 100644 index 0000000000..0dbc54f29b --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeleteHandler.java @@ -0,0 +1,87 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.handler; + +import org.apache.qpid.server.state.StateAwareMethodListener; +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.server.queue.QueueRegistry; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.exchange.ExchangeRegistry; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.protocol.AMQMethodEvent; +import org.apache.qpid.server.store.MessageStore; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.framing.QueueDeleteBody; +import org.apache.qpid.framing.QueueDeleteOkBody; +import org.apache.qpid.AMQException; + +public class QueueDeleteHandler implements StateAwareMethodListener +{ + private static final QueueDeleteHandler _instance = new QueueDeleteHandler(); + + public static QueueDeleteHandler getInstance() + { + return _instance; + } + + private final boolean _failIfNotFound; + private final MessageStore _store; + + public QueueDeleteHandler() + { + this(true); + } + + public QueueDeleteHandler(boolean failIfNotFound) + { + _failIfNotFound = failIfNotFound; + _store = ApplicationRegistry.getInstance().getMessageStore(); + + } + + public void methodReceived(AMQStateManager stateMgr, QueueRegistry queues, ExchangeRegistry exchanges, AMQProtocolSession session, AMQMethodEvent evt) throws AMQException + { + QueueDeleteBody body = evt.getMethod(); + AMQQueue queue; + if(body.queue == null) + { + queue = session.getChannel(evt.getChannelId()).getDefaultQueue(); + } + else + { + queue = queues.getQueue(body.queue); + } + + if(queue == null) + { + if(_failIfNotFound) + { + throw body.getChannelException(404, "Queue " + body.queue + " does not exist."); + } + } + else + { + int purged = queue.delete(body.ifUnused, body.ifEmpty); + _store.removeQueue(queue.getName()); + session.writeFrame(QueueDeleteOkBody.createAMQFrame(evt.getChannelId(), purged)); + } + } +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/handler/TxCommitHandler.java b/java/broker/src/main/java/org/apache/qpid/server/handler/TxCommitHandler.java new file mode 100644 index 0000000000..ac864cab6c --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/handler/TxCommitHandler.java @@ -0,0 +1,61 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.handler; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.TxCommitBody; +import org.apache.qpid.framing.TxCommitOkBody; +import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.exchange.ExchangeRegistry; +import org.apache.qpid.server.protocol.AMQMethodEvent; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.queue.QueueRegistry; +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.server.state.StateAwareMethodListener; + +public class TxCommitHandler implements StateAwareMethodListener +{ + private static TxCommitHandler _instance = new TxCommitHandler(); + + public static TxCommitHandler getInstance() + { + return _instance; + } + + private TxCommitHandler() + { + } + + public void methodReceived(AMQStateManager stateManager, QueueRegistry queueRegistry, + ExchangeRegistry exchangeRegistry, AMQProtocolSession protocolSession, + AMQMethodEvent evt) throws AMQException + { + + try{ + AMQChannel channel = protocolSession.getChannel(evt.getChannelId()); + channel.commit(); + protocolSession.writeFrame(TxCommitOkBody.createAMQFrame(evt.getChannelId())); + channel.processReturns(protocolSession); + }catch(AMQException e){ + throw evt.getMethod().getChannelException(e.getErrorCode(), "Failed to commit: " + e.getMessage()); + } + } +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/handler/TxRollbackHandler.java b/java/broker/src/main/java/org/apache/qpid/server/handler/TxRollbackHandler.java new file mode 100644 index 0000000000..475f6ecacf --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/handler/TxRollbackHandler.java @@ -0,0 +1,62 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.handler; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.TxRollbackBody; +import org.apache.qpid.framing.TxRollbackOkBody; +import org.apache.qpid.server.exchange.ExchangeRegistry; +import org.apache.qpid.server.protocol.AMQMethodEvent; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.queue.QueueRegistry; +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.server.state.StateAwareMethodListener; +import org.apache.qpid.server.AMQChannel; + +public class TxRollbackHandler implements StateAwareMethodListener +{ + private static TxRollbackHandler _instance = new TxRollbackHandler(); + + public static TxRollbackHandler getInstance() + { + return _instance; + } + + private TxRollbackHandler() + { + } + + public void methodReceived(AMQStateManager stateManager, QueueRegistry queueRegistry, + ExchangeRegistry exchangeRegistry, AMQProtocolSession protocolSession, + AMQMethodEvent evt) throws AMQException + { + try{ + AMQChannel channel = protocolSession.getChannel(evt.getChannelId()); + channel.rollback(); + protocolSession.writeFrame(TxRollbackOkBody.createAMQFrame(evt.getChannelId())); + //Now resend all the unacknowledged messages back to the original subscribers. + //(Must be done after the TxnRollback-ok response). + channel.resend(protocolSession); + }catch(AMQException e){ + throw evt.getMethod().getChannelException(e.getErrorCode(), "Failed to rollback: " + e.getMessage()); + } + } +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/handler/TxSelectHandler.java b/java/broker/src/main/java/org/apache/qpid/server/handler/TxSelectHandler.java new file mode 100644 index 0000000000..c30bc7d66f --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/handler/TxSelectHandler.java @@ -0,0 +1,53 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.handler; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.TxSelectBody; +import org.apache.qpid.framing.TxSelectOkBody; +import org.apache.qpid.server.exchange.ExchangeRegistry; +import org.apache.qpid.server.protocol.AMQMethodEvent; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.queue.QueueRegistry; +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.server.state.StateAwareMethodListener; + +public class TxSelectHandler implements StateAwareMethodListener +{ + private static TxSelectHandler _instance = new TxSelectHandler(); + + public static TxSelectHandler getInstance() + { + return _instance; + } + + private TxSelectHandler() + { + } + + public void methodReceived(AMQStateManager stateManager, QueueRegistry queueRegistry, + ExchangeRegistry exchangeRegistry, AMQProtocolSession protocolSession, + AMQMethodEvent evt) throws AMQException + { + protocolSession.getChannel(evt.getChannelId()).setTransactional(true); + protocolSession.writeFrame(TxSelectOkBody.createAMQFrame(evt.getChannelId())); + } +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/jms/JmsConsumer.java b/java/broker/src/main/java/org/apache/qpid/server/jms/JmsConsumer.java new file mode 100644 index 0000000000..41786e84ba --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/jms/JmsConsumer.java @@ -0,0 +1,110 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.jms; + +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.AMQException; + +public class JmsConsumer +{ + private int _prefetchValue; + + private PrefetchUnits _prefetchUnits; + + private boolean _noLocal; + + private boolean _autoAck; + + private boolean _exclusive; + + private AMQProtocolSession _protocolSession; + + public enum PrefetchUnits + { + OCTETS, + MESSAGES + } + + public int getPrefetchValue() + { + return _prefetchValue; + } + + public void setPrefetchValue(int prefetchValue) + { + _prefetchValue = prefetchValue; + } + + public PrefetchUnits getPrefetchUnits() + { + return _prefetchUnits; + } + + public void setPrefetchUnits(PrefetchUnits prefetchUnits) + { + _prefetchUnits = prefetchUnits; + } + + public boolean isNoLocal() + { + return _noLocal; + } + + public void setNoLocal(boolean noLocal) + { + _noLocal = noLocal; + } + + public boolean isAutoAck() + { + return _autoAck; + } + + public void setAutoAck(boolean autoAck) + { + _autoAck = autoAck; + } + + public boolean isExclusive() + { + return _exclusive; + } + + public void setExclusive(boolean exclusive) + { + _exclusive = exclusive; + } + + public AMQProtocolSession getProtocolSession() + { + return _protocolSession; + } + + public void setProtocolSession(AMQProtocolSession protocolSession) + { + _protocolSession = protocolSession; + } + + public void deliverMessage() throws AMQException + { + + } +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/management/AMQManagedObject.java b/java/broker/src/main/java/org/apache/qpid/server/management/AMQManagedObject.java new file mode 100644 index 0000000000..a2c2bd62a2 --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/management/AMQManagedObject.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.server.management; + +import javax.management.ListenerNotFoundException; +import javax.management.MBeanInfo; +import javax.management.MBeanNotificationInfo; +import javax.management.NotCompliantMBeanException; +import javax.management.NotificationBroadcaster; +import javax.management.NotificationBroadcasterSupport; +import javax.management.NotificationFilter; +import javax.management.NotificationListener; + +/** + * This class provides additinal feature of Notification Broadcaster to the + * DefaultManagedObject. + * @author Bhupendra Bhardwaj + * @version 0.1 + */ +public abstract class AMQManagedObject extends DefaultManagedObject + implements NotificationBroadcaster +{ + /** + * broadcaster support class + */ + protected NotificationBroadcasterSupport _broadcaster = new NotificationBroadcasterSupport(); + + /** + * sequence number for notifications + */ + protected long _notificationSequenceNumber = 0; + + protected MBeanInfo _mbeanInfo; + + protected AMQManagedObject(Class managementInterface, String typeName) + throws NotCompliantMBeanException + { + super(managementInterface, typeName); + buildMBeanInfo(); + } + + @Override + public MBeanInfo getMBeanInfo() + { + return _mbeanInfo; + } + + private void buildMBeanInfo() throws NotCompliantMBeanException + { + _mbeanInfo = new MBeanInfo(this.getClass().getName(), + MBeanIntrospector.getMBeanDescription(this.getClass()), + MBeanIntrospector.getMBeanAttributesInfo(getManagementInterface()), + MBeanIntrospector.getMBeanConstructorsInfo(this.getClass()), + MBeanIntrospector.getMBeanOperationsInfo(getManagementInterface()), + this.getNotificationInfo()); + } + + + + // notification broadcaster implementation + + public void addNotificationListener(NotificationListener listener, + NotificationFilter filter, + Object handback) + { + _broadcaster.addNotificationListener(listener, filter, handback); + } + + public void removeNotificationListener(NotificationListener listener) + throws ListenerNotFoundException + { + _broadcaster.removeNotificationListener(listener); + } + + public MBeanNotificationInfo[] getNotificationInfo() + { + return null; + } +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/management/DefaultManagedObject.java b/java/broker/src/main/java/org/apache/qpid/server/management/DefaultManagedObject.java new file mode 100644 index 0000000000..311eb8add9 --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/management/DefaultManagedObject.java @@ -0,0 +1,171 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.management; + +import org.apache.qpid.AMQException; +import org.apache.qpid.server.registry.ApplicationRegistry; + +import javax.management.JMException; +import javax.management.MalformedObjectNameException; +import javax.management.NotCompliantMBeanException; +import javax.management.ObjectName; +import javax.management.StandardMBean; + +/** + * Provides implementation of the boilerplate ManagedObject interface. Most managed objects should find it useful + * to extend this class rather than implementing ManagedObject from scratch. + * + */ +public abstract class DefaultManagedObject extends StandardMBean implements ManagedObject +{ + private Class _managementInterface; + + private String _typeName; + + protected DefaultManagedObject(Class managementInterface, String typeName) + throws NotCompliantMBeanException + { + super(managementInterface); + _managementInterface = managementInterface; + _typeName = typeName; + } + + public String getType() + { + return _typeName; + } + + public Class getManagementInterface() + { + return _managementInterface; + } + + public ManagedObject getParentObject() + { + return null; + } + + public void register() throws AMQException + { + try + { + ApplicationRegistry.getInstance().getManagedObjectRegistry().registerObject(this); + } + catch (JMException e) + { + throw new AMQException("Error registering managed object " + this + ": " + e, e); + } + } + + public void unregister() throws AMQException + { + try + { + ApplicationRegistry.getInstance().getManagedObjectRegistry().unregisterObject(this); + } + catch (JMException e) + { + throw new AMQException("Error unregistering managed object: " + this + ": " + e, e); + } + } + + public String toString() + { + return getObjectInstanceName() + "[" + getType() + "]"; + } + + /** + * Created the ObjectName as per the JMX Specs + * @return ObjectName + * @throws MalformedObjectNameException + */ + public ObjectName getObjectName() + throws MalformedObjectNameException + { + String name = getObjectInstanceName(); + StringBuffer objectName = new StringBuffer(ManagedObject.DOMAIN); + + objectName.append(":type="); + objectName.append(getHierarchicalType(this)); + + objectName.append(","); + objectName.append(getHierarchicalName(this)); + objectName.append("name=").append(name); + + return new ObjectName(objectName.toString()); + } + + private String getHierarchicalType(ManagedObject obj) + { + String parentType = null; + if (obj.getParentObject() != null) + { + parentType = getHierarchicalType(obj.getParentObject()).toString(); + return parentType + "." + obj.getType(); + } + else + return obj.getType(); + } + + private String getHierarchicalName(ManagedObject obj) + { + String parentName = null; + if (obj.getParentObject() != null) + { + parentName = obj.getParentObject().getType() + "=" + + obj.getParentObject().getObjectInstanceName() + ","+ + getHierarchicalName(obj.getParentObject()); + + return parentName; + } + else + return ""; + } + + protected static StringBuffer jmxEncode(StringBuffer jmxName, int attrPos) + { + for (int i = attrPos; i < jmxName.length(); i++) + { + if (jmxName.charAt(i) == ',') + { + jmxName.setCharAt(i, ';'); + } + else if (jmxName.charAt(i) == ':') + { + jmxName.setCharAt(i, '-'); + } + else if (jmxName.charAt(i) == '?' || + jmxName.charAt(i) == '*' || + jmxName.charAt(i) == '\\') + { + jmxName.insert(i, '\\'); + i++; + } + else if (jmxName.charAt(i) == '\n') + { + jmxName.insert(i, '\\'); + i++; + jmxName.setCharAt(i, 'n'); + } + } + return jmxName; + } +} \ No newline at end of file diff --git a/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java b/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java new file mode 100644 index 0000000000..140dbc31bb --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java @@ -0,0 +1,52 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.management; + +import org.apache.log4j.Logger; + +import javax.management.JMException; +import javax.management.MBeanServer; +import java.lang.management.ManagementFactory; + +public class JMXManagedObjectRegistry implements ManagedObjectRegistry +{ + private static final Logger _log = Logger.getLogger(JMXManagedObjectRegistry.class); + + private final MBeanServer _mbeanServer; + + public JMXManagedObjectRegistry() + { + _log.info("Initialising managed object registry using platform MBean server"); + // we use the platform MBean server currently but this must be changed or at least be configuurable + _mbeanServer = ManagementFactory.getPlatformMBeanServer(); + } + + public void registerObject(ManagedObject managedObject) throws JMException + { + _mbeanServer.registerMBean(managedObject, managedObject.getObjectName()); + } + + public void unregisterObject(ManagedObject managedObject) throws JMException + { + _mbeanServer.unregisterMBean(managedObject.getObjectName()); + } + +} \ No newline at end of file diff --git a/java/broker/src/main/java/org/apache/qpid/server/management/MBeanAttribute.java b/java/broker/src/main/java/org/apache/qpid/server/management/MBeanAttribute.java new file mode 100644 index 0000000000..a2e387a9e0 --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/management/MBeanAttribute.java @@ -0,0 +1,42 @@ +package org.apache.qpid.server.management; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Target; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +/** + * Annotation for MBean attributes. This should be used with getter or setter + * methods of attributes. + * @author Bhupendra Bhardwaj + * @version 0.1 + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +@Inherited +public @interface MBeanAttribute +{ + String name(); + String description(); +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/management/MBeanConstructor.java b/java/broker/src/main/java/org/apache/qpid/server/management/MBeanConstructor.java new file mode 100644 index 0000000000..c2cafcd387 --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/management/MBeanConstructor.java @@ -0,0 +1,40 @@ +package org.apache.qpid.server.management; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Target; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +/** + * Annotation for MBean constructors. + * @author Bhupendra Bhardwaj + * @version 0.1 + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.CONSTRUCTOR) +@Inherited +public @interface MBeanConstructor +{ + String value(); +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/management/MBeanDescription.java b/java/broker/src/main/java/org/apache/qpid/server/management/MBeanDescription.java new file mode 100644 index 0000000000..e25ceeab5c --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/management/MBeanDescription.java @@ -0,0 +1,39 @@ +package org.apache.qpid.server.management; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Target; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +/** + * Annotation for MBean class. + * @author Bhupendra Bhardwaj + * @version 0.1 + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +@Inherited +public @interface MBeanDescription { + String value(); +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/management/MBeanIntrospector.java b/java/broker/src/main/java/org/apache/qpid/server/management/MBeanIntrospector.java new file mode 100644 index 0000000000..b8235a0808 --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/management/MBeanIntrospector.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.server.management; + +import javax.management.MBeanAttributeInfo; +import javax.management.MBeanConstructorInfo; +import javax.management.MBeanOperationInfo; +import javax.management.MBeanParameterInfo; +import javax.management.NotCompliantMBeanException; +import java.lang.annotation.Annotation; +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; + +/** + * This class is a utility class to introspect the MBean class and the management + * interface class for various purposes. + * @author Bhupendra Bhardwaj + * @version 0.1 + */ +class MBeanIntrospector { + + private static final String _defaultAttributeDescription = "Management attribute"; + private static final String _defaultOerationDescription = "Management operation"; + private static final String _defaultConstructorDescription = "MBean constructor"; + private static final String _defaultMbeanDescription = "Management interface of the MBean"; + + /** + * Introspects the management interface class for MBean attributes. + * @param interfaceClass + * @return MBeanAttributeInfo[] + * @throws NotCompliantMBeanException + */ + static MBeanAttributeInfo[] getMBeanAttributesInfo(Class interfaceClass) + throws NotCompliantMBeanException + { + List attributesList = new ArrayList(); + + /** + * Using reflection, all methods of the managemetn interface will be analysed, + * and MBeanInfo will be created. + */ + for (Method method : interfaceClass.getMethods()) + { + int argCount = method.getParameterTypes().length; + String name = method.getName(); + Class resultType = method.getReturnType(); + MBeanAttributeInfo attributeInfo = null; + + if (isAttributeGetterMethod(method)) + { + String desc = getAttributeDescription(method); + attributeInfo = new MBeanAttributeInfo(name.substring(3), + resultType.getName(), + desc, + true, + false, + false); + int index = getIndexIfAlreadyExists(attributeInfo, attributesList); + if (index == -1) + { + attributesList.add(attributeInfo); + } + else + { + attributeInfo = new MBeanAttributeInfo(name.substring(3), + resultType.getName(), + desc, + true, + true, + false); + attributesList.set(index, attributeInfo); + } + } + else if (isAttributeSetterMethod(method)) + { + String desc = getAttributeDescription(method); + attributeInfo = new MBeanAttributeInfo(name.substring(3), + method.getParameterTypes()[0].getName(), + desc, + false, + true, + false); + int index = getIndexIfAlreadyExists(attributeInfo, attributesList); + if (index == -1) + { + attributesList.add(attributeInfo); + } + else + { + attributeInfo = new MBeanAttributeInfo(name.substring(3), + method.getParameterTypes()[0].getName(), + desc, + true, + true, + false); + attributesList.set(index, attributeInfo); + } + } + else if (isAttributeBoolean(method)) + { + attributeInfo = new MBeanAttributeInfo(name.substring(2), + resultType.getName(), + getAttributeDescription(method), + true, + false, + true); + attributesList.add(attributeInfo); + } + } + + return attributesList.toArray(new MBeanAttributeInfo[0]); + } + + /** + * Introspects the management interface class for management operations. + * @param interfaceClass + * @return MBeanOperationInfo[] + */ + static MBeanOperationInfo[] getMBeanOperationsInfo(Class interfaceClass) + { + List operationsList = new ArrayList(); + + for (Method method : interfaceClass.getMethods()) + { + if (!isAttributeGetterMethod(method) && + !isAttributeSetterMethod(method) && + !isAttributeBoolean(method)) + { + operationsList.add(getOperationInfo(method)); + } + } + + return operationsList.toArray(new MBeanOperationInfo[0]); + } + + /** + * Checks if the method is an attribute getter method. + * @param method + * @return true if the method is an attribute getter method. + */ + private static boolean isAttributeGetterMethod(Method method) + { + if (!(method.getName().equals("get")) && + method.getName().startsWith("get") && + method.getParameterTypes().length == 0 && + !method.getReturnType().equals(void.class)) + { + return true; + } + + return false; + } + + /** + * Checks if the method is an attribute setter method. + * @param method + * @return true if the method is an attribute setter method. + */ + private static boolean isAttributeSetterMethod(Method method) + { + if (!(method.getName().equals("set")) && + method.getName().startsWith("set") && + method.getParameterTypes().length == 1 && + method.getReturnType().equals(void.class)) + { + return true; + } + + return false; + } + + /** + * Checks if the attribute is a boolean and the method is a isX kind og method. + * @param method + * @return true if the method is an attribute isX type of method + */ + private static boolean isAttributeBoolean(Method method) + { + if (!(method.getName().equals("is")) && + method.getName().startsWith("is") && + method.getParameterTypes().length == 0 && + method.getReturnType().equals(boolean.class)) + { + return true; + } + + return false; + } + + /** + * Helper method to retrieve the attribute index from the list of attributes. + * @param attribute + * @param list + * @return attribute index no. -1 if attribtue doesn't exist + * @throws NotCompliantMBeanException + */ + private static int getIndexIfAlreadyExists(MBeanAttributeInfo attribute, + List list) + throws NotCompliantMBeanException + { + String exceptionMsg = "Conflicting attribute methods for attribute " + attribute.getName(); + + for (MBeanAttributeInfo memberAttribute : list) + { + if (attribute.getName().equals(memberAttribute.getName())) + { + if (!attribute.getType().equals(memberAttribute.getType())) + { + throw new NotCompliantMBeanException(exceptionMsg); + } + if (attribute.isReadable() && memberAttribute.isReadable()) + { + if (attribute.isIs() != memberAttribute.isIs()) + { + throw new NotCompliantMBeanException(exceptionMsg); + } + } + + return list.indexOf(memberAttribute); + } + } + + return -1; + } + + /** + * Retrieves the attribute description from annotation + * @param attributeMethod + * @return attribute description + */ + private static String getAttributeDescription(Method attributeMethod) + { + MBeanAttribute anno = attributeMethod.getAnnotation(MBeanAttribute.class); + if (anno != null) + { + return anno.description(); + } + return _defaultAttributeDescription; + } + + /** + * Introspects the method to retrieve the operation information. + * @param operation + * @return MBeanOperationInfo + */ + private static MBeanOperationInfo getOperationInfo(Method operation) + { + MBeanOperationInfo operationInfo = null; + Class returnType = operation.getReturnType(); + + MBeanParameterInfo[] paramsInfo = getParametersInfo(operation.getParameterAnnotations(), + operation.getParameterTypes()); + + String operationDesc = _defaultOerationDescription; + int impact = MBeanOperationInfo.UNKNOWN; + + if (operation.getAnnotation(MBeanOperation.class) != null) + { + operationDesc = operation.getAnnotation(MBeanOperation.class).description(); + impact = operation.getAnnotation(MBeanOperation.class).impact(); + } + operationInfo = new MBeanOperationInfo(operation.getName(), + operationDesc, + paramsInfo, + returnType.getName(), + impact); + + return operationInfo; + } + + /** + * Constructs the parameter info. + * @param paramsAnno + * @param paramTypes + * @return MBeanParameterInfo[] + */ + private static MBeanParameterInfo[] getParametersInfo(Annotation[][] paramsAnno, + Class[] paramTypes) + { + int noOfParams = paramsAnno.length; + + MBeanParameterInfo[] paramsInfo = new MBeanParameterInfo[noOfParams]; + + for (int i = 0; i < noOfParams; i++) + { + MBeanParameterInfo paramInfo = null; + String type = paramTypes[i].getName(); + for (Annotation anno : paramsAnno[i]) + { + String name,desc; + if (MBeanOperationParameter.class.isInstance(anno)) + { + name = MBeanOperationParameter.class.cast(anno).name(); + desc = MBeanOperationParameter.class.cast(anno).description(); + paramInfo = new MBeanParameterInfo(name, type, desc); + } + } + + + if (paramInfo == null) + { + paramInfo = new MBeanParameterInfo("p " + (i + 1), type, "parameter " + (i + 1)); + } + if (paramInfo != null) + paramsInfo[i] = paramInfo; + } + + return paramsInfo; + } + + /** + * Introspects the MBean class for constructors + * @param implClass + * @return MBeanConstructorInfo[] + */ + static MBeanConstructorInfo[] getMBeanConstructorsInfo(Class implClass) + { + List constructors = new ArrayList(); + + for (Constructor cons : implClass.getConstructors()) + { + MBeanConstructorInfo constructorInfo = getMBeanConstructorInfo(cons); + //MBeanConstructorInfo constructorInfo = new MBeanConstructorInfo("desc", cons); + if (constructorInfo != null) + constructors.add(constructorInfo); + } + + return constructors.toArray(new MBeanConstructorInfo[0]); + } + + /** + * Retrieves the constructor info from given constructor. + * @param cons + * @return MBeanConstructorInfo + */ + private static MBeanConstructorInfo getMBeanConstructorInfo(Constructor cons) + { + String desc = null; + Annotation anno = cons.getAnnotation(MBeanConstructor.class); + if (anno != null && MBeanConstructor.class.isInstance(anno)) + { + desc = MBeanConstructor.class.cast(anno).value(); + } + + //MBeanParameterInfo[] paramsInfo = getParametersInfo(cons.getParameterAnnotations(), + // cons.getParameterTypes()); + + return new MBeanConstructorInfo(cons.getName(), + desc != null ? _defaultConstructorDescription : desc , + null); + } + + /** + * Retrieves the description from the annotations of given class + * @param annotatedClass + * @return class description + */ + static String getMBeanDescription(Class annotatedClass) + { + Annotation anno = annotatedClass.getAnnotation(MBeanDescription.class); + if (anno != null && MBeanDescription.class.isInstance(anno)) + { + return MBeanDescription.class.cast(anno).value(); + } + return _defaultMbeanDescription; + } + +} \ No newline at end of file diff --git a/java/broker/src/main/java/org/apache/qpid/server/management/MBeanOperation.java b/java/broker/src/main/java/org/apache/qpid/server/management/MBeanOperation.java new file mode 100644 index 0000000000..ebeccadf70 --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/management/MBeanOperation.java @@ -0,0 +1,43 @@ +package org.apache.qpid.server.management; + +import javax.management.MBeanOperationInfo; +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Target; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +/** + * Annotation for MBean operations. + * @author Bhupendra Bhardwaj + * @version 0.1 + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +@Inherited +public @interface MBeanOperation +{ + String name(); + String description(); + int impact() default MBeanOperationInfo.INFO; +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/management/MBeanOperationParameter.java b/java/broker/src/main/java/org/apache/qpid/server/management/MBeanOperationParameter.java new file mode 100644 index 0000000000..adb3c651df --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/management/MBeanOperationParameter.java @@ -0,0 +1,38 @@ +package org.apache.qpid.server.management; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.lang.annotation.ElementType; +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +/** + * Annotation for MBean operation parameters. + * @author Bhupendra Bhardwaj + * @version 0.1 + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.PARAMETER) +public @interface MBeanOperationParameter { + String name(); + String description(); +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/management/Managable.java b/java/broker/src/main/java/org/apache/qpid/server/management/Managable.java new file mode 100644 index 0000000000..166a2a376d --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/management/Managable.java @@ -0,0 +1,34 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.management; + +/** + * Any object that can return a related MBean should implement this interface. + * + * This enables other classes to get the managed object, which in turn is useful when + * constructing relationships between managed objects without having to maintain + * separate data structures containing MBeans. + * + */ +public interface Managable +{ + ManagedObject getManagedObject(); +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/management/ManagedBroker.java b/java/broker/src/main/java/org/apache/qpid/server/management/ManagedBroker.java new file mode 100644 index 0000000000..266fb62fd8 --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/management/ManagedBroker.java @@ -0,0 +1,98 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +package org.apache.qpid.server.management; + +import javax.management.JMException; +import javax.management.MBeanOperationInfo; +import java.io.IOException; + +/** + * The ManagedBroker is the management interface to expose management + * features of the Broker. + * + * @author Bhupendra Bhardwaj + * @version 0.1 + */ +public interface ManagedBroker +{ + static final String TYPE = "BrokerManager"; + + /** + * Creates a new Exchange. + * @param name + * @param type + * @param durable + * @param passive + * @throws IOException + * @throws JMException + */ + @MBeanOperation(name="createNewExchange", description="Creates a new Exchange", + impact= MBeanOperationInfo.ACTION) + void createNewExchange(@MBeanOperationParameter(name="name", description="Name of the new exchange")String name, + @MBeanOperationParameter(name="excahnge type", description="Type of the exchange")String type, + @MBeanOperationParameter(name="durable", description="true if the Exchang should be durable")boolean durable, + @MBeanOperationParameter(name="passive", description="true of the Exchange should be passive")boolean passive) + throws IOException, JMException; + + /** + * unregisters all the channels, queuebindings etc and unregisters + * this exchange from managed objects. + * @param exchange + * @throws IOException + * @throws JMException + */ + @MBeanOperation(name="unregisterExchange", + description="Unregisters all the related channels and queuebindings of this exchange", + impact= MBeanOperationInfo.ACTION) + void unregisterExchange(@MBeanOperationParameter(name="exchange name", description="Name of the exchange")String exchange) + throws IOException, JMException; + + /** + * Create a new Queue on the Broker server + * @param queueName + * @param durable + * @param owner + * @param autoDelete + * @throws IOException + * @throws JMException + */ + @MBeanOperation(name="createQueue", description="Create a new Queue on the Broker server", + impact= MBeanOperationInfo.ACTION) + void createQueue(@MBeanOperationParameter(name="queue name", description="Name of the new queue")String queueName, + @MBeanOperationParameter(name="durable", description="true if the queue should be durable")boolean durable, + @MBeanOperationParameter(name="owner", description="Owner name")String owner, + @MBeanOperationParameter(name="autoDelete", description="true if the queue should be auto delete") boolean autoDelete) + throws IOException, JMException; + + /** + * Unregisters the Queue bindings, removes the subscriptions and unregisters + * from the managed objects. + * @param queueName + * @throws IOException + * @throws JMException + */ + @MBeanOperation(name="deleteQueue", + description="Unregisters the Queue bindings, removes the subscriptions and deletes the queue", + impact= MBeanOperationInfo.ACTION) + void deleteQueue(@MBeanOperationParameter(name="queue name", description="Name of the queue")String queueName) + throws IOException, JMException; +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/management/ManagedObject.java b/java/broker/src/main/java/org/apache/qpid/server/management/ManagedObject.java new file mode 100644 index 0000000000..f512c2dea8 --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/management/ManagedObject.java @@ -0,0 +1,58 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.management; + +import org.apache.qpid.AMQException; + +import javax.management.ObjectName; +import javax.management.MalformedObjectNameException; + +/** + * This should be implemented by all Managable objects. + */ +public interface ManagedObject +{ + static final String DOMAIN = "org.apache.qpid"; + + /** + * @return the name that uniquely identifies this object instance. It must be + * unique only among objects of this type at this level in the hierarchy so + * the uniqueness should not be too difficult to ensure. + */ + String getObjectInstanceName(); + + String getType(); + + Class getManagementInterface(); + + ManagedObject getParentObject(); + + void register() throws AMQException; + + void unregister() throws AMQException; + + /** + * Returns the ObjectName required for the mbeanserver registration. + * @return ObjectName + * @throws MalformedObjectNameException + */ + ObjectName getObjectName() throws MalformedObjectNameException; +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/management/ManagedObjectRegistry.java b/java/broker/src/main/java/org/apache/qpid/server/management/ManagedObjectRegistry.java new file mode 100644 index 0000000000..32298f05e3 --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/management/ManagedObjectRegistry.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.server.management; + +import javax.management.JMException; + +/** + * Handles the registration (and unregistration and so on) of managed objects. + * + * Managed objects are responsible for exposting attributes, operations and notifications. They will expose + * these outside the JVM therefore it is important not to use implementation objects directly as managed objects. + * Instead, creating inner classes and exposing those is an effective way of exposing internal state in a + * controlled way. + * + * Although we do not explictly use them while targetting Java 5, the enhanced MXBean approach in Java 6 will + * be the obvious choice for managed objects. + * + */ +public interface ManagedObjectRegistry +{ + void registerObject(ManagedObject managedObject) throws JMException; + + void unregisterObject(ManagedObject managedObject) throws JMException; +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/management/ManagementConfiguration.java b/java/broker/src/main/java/org/apache/qpid/server/management/ManagementConfiguration.java new file mode 100644 index 0000000000..042f626e8b --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/management/ManagementConfiguration.java @@ -0,0 +1,30 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.management; + +import org.apache.qpid.configuration.Configured; + +public class ManagementConfiguration +{ + @Configured(path = "management.enabled", + defaultValue = "true") + public boolean enabled; +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/management/NoopManagedObjectRegistry.java b/java/broker/src/main/java/org/apache/qpid/server/management/NoopManagedObjectRegistry.java new file mode 100644 index 0000000000..121c992c4f --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/management/NoopManagedObjectRegistry.java @@ -0,0 +1,48 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.management; + +import org.apache.log4j.Logger; + +import javax.management.JMException; + +/** + * This managed object registry does not actually register MBeans. This can be used in tests when management is + * not required or when management has been disabled. + * + */ +public class NoopManagedObjectRegistry implements ManagedObjectRegistry +{ + private static final Logger _log = Logger.getLogger(NoopManagedObjectRegistry.class); + + public NoopManagedObjectRegistry() + { + _log.info("Management is disabled"); + } + + public void registerObject(ManagedObject managedObject) throws JMException + { + } + + public void unregisterObject(ManagedObject managedObject) throws JMException + { + } +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMethodEvent.java b/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMethodEvent.java new file mode 100644 index 0000000000..3d12828900 --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMethodEvent.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.server.protocol; + +import org.apache.qpid.framing.AMQMethodBody; + +/** + * An event that is passed to AMQMethodListeners describing a particular method. + * It supplies the: + *
  • channel id
  • + *
  • protocol method
  • + * to listeners. This means that listeners do not need to be stateful. + * + * In the StateAwareMethodListener, other useful objects such as the protocol session + * are made available. + * + */ +public class AMQMethodEvent +{ + private final M _method; + + private final int _channelId; + + public AMQMethodEvent(int channelId, M method) + { + _channelId = channelId; + _method = method; + } + + public M getMethod() + { + return _method; + } + + public int getChannelId() + { + return _channelId; + } + + public String toString() + { + StringBuilder buf = new StringBuilder("Method event: "); + buf.append("\nChannel id: ").append(_channelId); + buf.append("\nMethod: ").append(_method); + return buf.toString(); + } +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMethodListener.java b/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMethodListener.java new file mode 100644 index 0000000000..d2062d3c17 --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMethodListener.java @@ -0,0 +1,55 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.protocol; + +import org.apache.qpid.AMQException; +import org.apache.qpid.server.queue.QueueRegistry; +import org.apache.qpid.server.exchange.ExchangeRegistry; +import org.apache.qpid.framing.AMQMethodBody; + +/** + * Interface that allows classes to register for interest in protocol method frames. + * + */ +public interface AMQMethodListener +{ + /** + * Invoked when a method frame has been received + * @param evt the event that contains the method and channel + * @param protocolSession the protocol session associated with the event + * @return true if the handler has processed the method frame, false otherwise. Note + * that this does not prohibit the method event being delivered to subsequent listeners + * but can be used to determine if nobody has dealt with an incoming method frame. + * @throws AMQException if an error has occurred. This exception will be delivered + * to all registered listeners using the error() method (see below) allowing them to + * perform cleanup if necessary. + */ + boolean methodReceived(AMQMethodEvent evt, + AMQProtocolSession protocolSession, + QueueRegistry queueRegistry, + ExchangeRegistry exchangeRegistry) throws AMQException; + + /** + * Callback when an error has occurred. Allows listeners to clean up. + * @param e + */ + void error(AMQException e); +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java b/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java new file mode 100644 index 0000000000..966af77d64 --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java @@ -0,0 +1,700 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.protocol; + +import org.apache.log4j.Logger; +import org.apache.mina.common.IdleStatus; +import org.apache.mina.common.IoSession; +import org.apache.mina.transport.vmpipe.VmPipeAddress; +import org.apache.qpid.AMQChannelException; +import org.apache.qpid.AMQException; +import org.apache.qpid.codec.AMQCodecFactory; +import org.apache.qpid.codec.AMQDecoder; +import org.apache.qpid.framing.AMQDataBlock; +import org.apache.qpid.framing.AMQFrame; +import org.apache.qpid.framing.AMQMethodBody; +import org.apache.qpid.framing.ConnectionStartBody; +import org.apache.qpid.framing.ContentBody; +import org.apache.qpid.framing.ContentHeaderBody; +import org.apache.qpid.framing.HeartbeatBody; +import org.apache.qpid.framing.ProtocolInitiation; +import org.apache.qpid.framing.ProtocolVersionList; +import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.RequiredDeliveryException; +import org.apache.qpid.server.exchange.ExchangeRegistry; +import org.apache.qpid.server.management.AMQManagedObject; +import org.apache.qpid.server.management.MBeanConstructor; +import org.apache.qpid.server.management.MBeanDescription; +import org.apache.qpid.server.management.Managable; +import org.apache.qpid.server.management.ManagedObject; +import org.apache.qpid.server.queue.QueueRegistry; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.state.AMQStateManager; + +import javax.management.JMException; +import javax.management.MBeanException; +import javax.management.MBeanNotificationInfo; +import javax.management.NotCompliantMBeanException; +import javax.management.Notification; +import javax.management.monitor.MonitorNotification; +import javax.management.openmbean.CompositeData; +import javax.management.openmbean.CompositeDataSupport; +import javax.management.openmbean.CompositeType; +import javax.management.openmbean.OpenDataException; +import javax.management.openmbean.OpenType; +import javax.management.openmbean.SimpleType; +import javax.management.openmbean.TabularData; +import javax.management.openmbean.TabularDataSupport; +import javax.management.openmbean.TabularType; +import javax.security.sasl.SaslServer; +import java.net.InetSocketAddress; +import java.net.SocketAddress; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.CopyOnWriteArraySet; + +public class AMQMinaProtocolSession implements AMQProtocolSession, + ProtocolVersionList, + Managable +{ + private static final Logger _logger = Logger.getLogger(AMQProtocolSession.class); + + private final IoSession _minaProtocolSession; + + private String _contextKey; + + private final Map _channelMap = new HashMap(); + + private final CopyOnWriteArraySet _frameListeners = new CopyOnWriteArraySet(); + + private final AMQStateManager _stateManager; + + private final QueueRegistry _queueRegistry; + + private final ExchangeRegistry _exchangeRegistry; + + private AMQCodecFactory _codecFactory; + + private ManagedAMQProtocolSession _managedObject; + + private SaslServer _saslServer; + + private Object _lastReceived; + + private Object _lastSent; + + private boolean _closed; + + private long _maxNoOfChannels = 1000; + + /* AMQP Version for this session */ + + private byte _major; + private byte _minor; + + public ManagedObject getManagedObject() + { + return _managedObject; + } + + /** + * This class implements the management interface (is an MBean). In order to + * make more attributes, operations and notifications available over JMX simply + * augment the ManagedConnection interface and add the appropriate implementation here. + */ + @MBeanDescription("Management Bean for an AMQ Broker Connection") + private final class ManagedAMQProtocolSession extends AMQManagedObject + implements ManagedConnection + { + private String _name = null; + /** + * Represents the channel attributes sent with channel data. + */ + private String[] _channelAtttibuteNames = { "ChannelId", + "Transactional", + "DefaultQueue", + "UnacknowledgedMessageCount"}; + private String[] _channelAttributeDescriptions = { "Channel Identifier", + "is Channel Transactional?", + "Default Queue Name", + "Unacknowledged Message Count"}; + private OpenType[] _channelAttributeTypes = { SimpleType.INTEGER, + SimpleType.BOOLEAN, + SimpleType.STRING, + SimpleType.INTEGER}; + + private String[] _indexNames = { "ChannelId" }; //Channels in the list will be indexed according to channelId. + private CompositeType _channelType = null; // represents the data type for channel data + private TabularType _channelsType = null; // Datatype for list of channelsType + private TabularDataSupport _channelsList = null; + + @MBeanConstructor("Creates an MBean exposing an AMQ Broker Connection") + public ManagedAMQProtocolSession() throws NotCompliantMBeanException + { + super(ManagedConnection.class, ManagedConnection.TYPE); + init(); + } + + /** + * initialises the CompositeTypes and TabularType attributes. + */ + private void init() + { + String remote = getRemoteAddress(); + remote = "anonymous".equals(remote) ? remote + hashCode() : remote; + _name = jmxEncode(new StringBuffer(remote), 0).toString(); + + try + { + _channelType = new CompositeType("channel", + "Channel Details", + _channelAtttibuteNames, + _channelAttributeDescriptions, + _channelAttributeTypes); + + _channelsType = new TabularType("channelsType", + "List of available channels", + _channelType, + _indexNames); + } + catch(OpenDataException ex) + { + // It should never occur. + _logger.error("OpenDataTypes could not be created.", ex); + throw new RuntimeException(ex); + } + } + + public Date getLastIoTime() + { + return new Date(_minaProtocolSession.getLastIoTime()); + } + + public String getRemoteAddress() + { + return _minaProtocolSession.getRemoteAddress().toString(); + } + + public Long getWrittenBytes() + { + return _minaProtocolSession.getWrittenBytes(); + } + + public Long getReadBytes() + { + return _minaProtocolSession.getReadBytes(); + } + + public Long getMaximumNumberOfAllowedChannels() + { + return _maxNoOfChannels; + } + + public void setMaximumNumberOfAllowedChannels(Long value) + { + _maxNoOfChannels = value; + } + + public String getObjectInstanceName() + { + return _name; + } + + public void commitTransactions(int channelId) throws JMException + { + try + { + AMQChannel channel = _channelMap.get(channelId); + if (channel == null) + { + throw new JMException("The channel (channel Id = " + channelId + ") does not exist"); + } + if (channel.isTransactional()) + { + channel.commit(); + } + } + catch(AMQException ex) + { + throw new MBeanException(ex, ex.toString()); + } + } + + public void rollbackTransactions(int channelId) throws JMException + { + try + { + AMQChannel channel = _channelMap.get(channelId); + if (channel == null) + { + throw new JMException("The channel (channel Id = " + channelId + ") does not exist"); + } + if (channel.isTransactional()) + { + channel.rollback(); + } + } + catch(AMQException ex) + { + throw new MBeanException(ex, ex.toString()); + } + } + + /** + * Creates the list of channels in tabular form from the _channelMap. + * @return list of channels in tabular form. + * @throws OpenDataException + */ + public TabularData getChannels() throws OpenDataException + { + _channelsList = new TabularDataSupport(_channelsType); + + for (Map.Entry entry : _channelMap.entrySet()) + { + AMQChannel channel = entry.getValue(); + Object[] itemValues = {channel.getChannelId(), + channel.isTransactional(), + (channel.getDefaultQueue() != null) ? channel.getDefaultQueue().getName() : null, + channel.getUnacknowledgedMessageMap().size()}; + + CompositeData channelData = new CompositeDataSupport(_channelType, + _channelAtttibuteNames, + itemValues); + + _channelsList.put(channelData); + } + + return _channelsList; + } + + public void closeChannel(int id) + throws Exception + { + try + { + AMQMinaProtocolSession.this.closeChannel(id); + } + catch (AMQException ex) + { + throw new Exception(ex.toString()); + } + } + + public void closeConnection() + throws Exception + { + try + { + AMQMinaProtocolSession.this.closeSession(); + } + catch (AMQException ex) + { + throw new Exception(ex.toString()); + } + } + + @Override + public MBeanNotificationInfo[] getNotificationInfo() + { + String[] notificationTypes = new String[] + {MonitorNotification.THRESHOLD_VALUE_EXCEEDED}; + String name = MonitorNotification.class.getName(); + String description = "An attribute of this MBean has reached threshold value"; + MBeanNotificationInfo info1 = new MBeanNotificationInfo(notificationTypes, + name, + description); + + return new MBeanNotificationInfo[] {info1}; + } + + private void checkForNotification() + { + int channelsCount = _channelMap.size(); + if (channelsCount >= getMaximumNumberOfAllowedChannels()) + { + Notification n = new Notification( + MonitorNotification.THRESHOLD_VALUE_EXCEEDED, + this, + ++_notificationSequenceNumber, + System.currentTimeMillis(), + "ChannelsCount = " + channelsCount + ", ChannelsCount has reached the threshold value"); + + _broadcaster.sendNotification(n); + } + } + + } // End of MBean class + + public AMQMinaProtocolSession(IoSession session, QueueRegistry queueRegistry, ExchangeRegistry exchangeRegistry, + AMQCodecFactory codecFactory) + throws AMQException + { + this(session, queueRegistry, exchangeRegistry, codecFactory, new AMQStateManager()); + } + + public AMQMinaProtocolSession(IoSession session, QueueRegistry queueRegistry, ExchangeRegistry exchangeRegistry, + AMQCodecFactory codecFactory, AMQStateManager stateManager) + throws AMQException + { + _stateManager = stateManager; + _minaProtocolSession = session; + session.setAttachment(this); + _frameListeners.add(_stateManager); + _queueRegistry = queueRegistry; + _exchangeRegistry = exchangeRegistry; + _codecFactory = codecFactory; + _managedObject = createMBean(); + _managedObject.register(); + } + + private ManagedAMQProtocolSession createMBean() throws AMQException + { + try + { + return new ManagedAMQProtocolSession(); + } + catch(NotCompliantMBeanException ex) + { + _logger.error("AMQProtocolSession MBean creation has failed.", ex); + throw new AMQException("AMQProtocolSession MBean creation has failed.", ex); + } + } + + public static AMQProtocolSession getAMQProtocolSession(IoSession minaProtocolSession) + { + return (AMQProtocolSession) minaProtocolSession.getAttachment(); + } + + public void dataBlockReceived(AMQDataBlock message) + throws Exception + { + _lastReceived = message; + if (message instanceof ProtocolInitiation) + { + ProtocolInitiation pi = (ProtocolInitiation) message; + // this ensures the codec never checks for a PI message again + ((AMQDecoder)_codecFactory.getDecoder()).setExpectProtocolInitiation(false); + try { + pi.checkVersion(this); // Fails if not correct + // This sets the protocol version (and hence framing classes) for this session. + _major = pi.protocolMajor; + _minor = pi.protocolMinor; + String mechanisms = ApplicationRegistry.getInstance().getAuthenticationManager().getMechanisms(); + String locales = "en_US"; + AMQFrame response = ConnectionStartBody.createAMQFrame((short)0, pi.protocolMajor, pi.protocolMinor, null, + mechanisms.getBytes(), locales.getBytes()); + _minaProtocolSession.write(response); + } catch (AMQException e) { + _logger.error("Received incorrect protocol initiation", e); + /* Find last protocol version in protocol version list. Make sure last protocol version + listed in the build file (build-module.xml) is the latest version which will be used + here. */ + int i = pv.length - 1; + _minaProtocolSession.write(new ProtocolInitiation(pv[i][PROTOCOL_MAJOR], pv[i][PROTOCOL_MINOR])); + // TODO: Close connection (but how to wait until message is sent?) + } + } + else + { + AMQFrame frame = (AMQFrame) message; + + if (frame.bodyFrame instanceof AMQMethodBody) + { + methodFrameReceived(frame); + } + else + { + try + { + contentFrameReceived(frame); + } + catch (RequiredDeliveryException e) + { + //need to return the message: + _logger.info("Returning message to " + this + " channel " + frame.channel + + ": " + e.getMessage()); + writeFrame(e.getReturnMessage(frame.channel)); + } + } + } + } + + private void methodFrameReceived(AMQFrame frame) + { + if (_logger.isDebugEnabled()) + { + _logger.debug("Method frame received: " + frame); + } + final AMQMethodEvent evt = new AMQMethodEvent(frame.channel, + (AMQMethodBody)frame.bodyFrame); + try + { + boolean wasAnyoneInterested = false; + for (AMQMethodListener listener : _frameListeners) + { + wasAnyoneInterested = listener.methodReceived(evt, this, _queueRegistry, _exchangeRegistry) || + wasAnyoneInterested; + } + if (!wasAnyoneInterested) + { + throw new AMQException("AMQMethodEvent " + evt + " was not processed by any listener."); + } + } + catch (AMQChannelException e) + { + _logger.error("Closing channel due to: " + e.getMessage()); + writeFrame(e.getCloseFrame(frame.channel)); + } + catch (AMQException e) + { + for (AMQMethodListener listener : _frameListeners) + { + listener.error(e); + } + _minaProtocolSession.close(); + } + } + + private void contentFrameReceived(AMQFrame frame) throws AMQException + { + if (frame.bodyFrame instanceof ContentHeaderBody) + { + contentHeaderReceived(frame); + } + else if (frame.bodyFrame instanceof ContentBody) + { + contentBodyReceived(frame); + } + else if (frame.bodyFrame instanceof HeartbeatBody) + { + _logger.debug("Received heartbeat from client"); + } + else + { + _logger.warn("Unrecognised frame " + frame.getClass().getName()); + } + } + + private void contentHeaderReceived(AMQFrame frame) throws AMQException + { + if (_logger.isDebugEnabled()) + { + _logger.debug("Content header frame received: " + frame); + } + getChannel(frame.channel).publishContentHeader((ContentHeaderBody)frame.bodyFrame); + } + + private void contentBodyReceived(AMQFrame frame) throws AMQException + { + if (_logger.isDebugEnabled()) + { + _logger.debug("Content body frame received: " + frame); + } + getChannel(frame.channel).publishContentBody((ContentBody)frame.bodyFrame); + } + + /** + * Convenience method that writes a frame to the protocol session. Equivalent + * to calling getProtocolSession().write(). + * + * @param frame the frame to write + */ + public void writeFrame(AMQDataBlock frame) + { + _lastSent = frame; + _minaProtocolSession.write(frame); + } + + public String getContextKey() + { + return _contextKey; + } + + public void setContextKey(String contextKey) + { + _contextKey = contextKey; + } + + public AMQChannel getChannel(int channelId) throws AMQException + { + return _channelMap.get(channelId); + } + + public void addChannel(AMQChannel channel) + { + _channelMap.put(channel.getChannelId(), channel); + _managedObject.checkForNotification(); + } + + /** + * Close a specific channel. This will remove any resources used by the channel, including: + *
    • any queue subscriptions (this may in turn remove queues if they are auto delete
    • + *
    + * @param channelId id of the channel to close + * @throws AMQException if an error occurs closing the channel + * @throws IllegalArgumentException if the channel id is not valid + */ + public void closeChannel(int channelId) throws AMQException + { + final AMQChannel channel = _channelMap.get(channelId); + if (channel == null) + { + throw new IllegalArgumentException("Unknown channel id"); + } + else + { + try + { + channel.close(this); + } + finally + { + _channelMap.remove(channelId); + } + } + } + + /** + * In our current implementation this is used by the clustering code. + * @param channelId + */ + public void removeChannel(int channelId) + { + _channelMap.remove(channelId); + } + + /** + * Initialise heartbeats on the session. + * @param delay delay in seconds (not ms) + */ + public void initHeartbeats(int delay) + { + if(delay > 0) + { + _minaProtocolSession.setIdleTime(IdleStatus.WRITER_IDLE, delay); + _minaProtocolSession.setIdleTime(IdleStatus.READER_IDLE, HeartbeatConfig.getInstance().getTimeout(delay)); + } + } + + /** + * Closes all channels that were opened by this protocol session. This frees up all resources + * used by the channel. + * @throws AMQException if an error occurs while closing any channel + */ + private void closeAllChannels() throws AMQException + { + for (AMQChannel channel : _channelMap.values()) + { + channel.close(this); + } + } + + /** + * This must be called when the session is _closed in order to free up any resources + * managed by the session. + */ + public void closeSession() throws AMQException + { + if(!_closed) + { + _closed = true; + closeAllChannels(); + if (_managedObject != null) + { + _managedObject.unregister(); + } + } + } + + public String toString() + { + return "AMQProtocolSession(" + _minaProtocolSession.getRemoteAddress() + ")"; + } + + public String dump() + { + return this + " last_sent=" + _lastSent + " last_received=" + _lastReceived; + } + + /** + * @return an object that can be used to identity + */ + public Object getKey() + { + return _minaProtocolSession.getRemoteAddress(); + } + + /** + * Get the fully qualified domain name of the local address to which this session is bound. Since some servers + * may be bound to multiple addresses this could vary depending on the acceptor this session was created from. + * + * @return a String FQDN + */ + public String getLocalFQDN() + { + SocketAddress address = _minaProtocolSession.getLocalAddress(); + // we use the vmpipe address in some tests hence the need for this rather ugly test. The host + // information is used by SASL primary. + if (address instanceof InetSocketAddress) + { + return ((InetSocketAddress)address).getHostName(); + } + else if (address instanceof VmPipeAddress) + { + return "vmpipe:" + ((VmPipeAddress)address).getPort(); + } + else + { + throw new IllegalArgumentException("Unsupported socket address class: " + address); + } + } + + public SaslServer getSaslServer() + { + return _saslServer; + } + + public void setSaslServer(SaslServer saslServer) + { + _saslServer = saslServer; + } + + /** + * Convenience methods for managing AMQP version. + * NOTE: Both major and minor will be set to 0 prior to protocol initiation. + */ + + public byte getAmqpMajor() + { + return _major; + } + + public byte getAmqpMinor() + { + return _minor; + } + + public boolean amqpVersionEquals(byte major, byte minor) + { + return _major == major && _minor == minor; + } +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPFastProtocolHandler.java b/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPFastProtocolHandler.java new file mode 100644 index 0000000000..18980f440b --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPFastProtocolHandler.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.server.protocol; + +import org.apache.qpid.AMQException; +import org.apache.qpid.codec.AMQCodecFactory; +import org.apache.qpid.framing.*; +import org.apache.qpid.server.exchange.ExchangeRegistry; +import org.apache.qpid.server.queue.QueueRegistry; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.registry.IApplicationRegistry; +import org.apache.qpid.server.transport.ConnectorConfiguration; +import org.apache.qpid.ssl.BogusSSLContextFactory; +import org.apache.log4j.Logger; +import org.apache.mina.common.ByteBuffer; +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.ProtocolCodecFilter; +import org.apache.mina.util.SessionUtil; + +import java.io.IOException; + + +/** + * The protocol handler handles "protocol events" for all connections. The state + * associated with an individual connection is accessed through the protocol session. + * + * We delegate all frame (message) processing to the AMQProtocolSession which wraps + * the state for the connection. + * + */ +public class AMQPFastProtocolHandler extends IoHandlerAdapter implements ProtocolVersionList +{ + private static final Logger _logger = Logger.getLogger(AMQPFastProtocolHandler.class); + + /** + * The registry of all queues. This is passed to frame listeners when frame + * events occur. + */ + private final QueueRegistry _queueRegistry; + + /** + * The registry of all exchanges. This is passed to frame listeners when frame + * events occur. + */ + private final ExchangeRegistry _exchangeRegistry; + + private boolean _useSSL; + + public AMQPFastProtocolHandler(Integer applicationRegistryInstance) + { + IApplicationRegistry registry = ApplicationRegistry.getInstance(applicationRegistryInstance); + + _queueRegistry = registry.getQueueRegistry(); + _exchangeRegistry = registry.getExchangeRegistry(); + _logger.debug("AMQPFastProtocolHandler created"); + } + + public AMQPFastProtocolHandler(QueueRegistry queueRegistry, + ExchangeRegistry exchangeRegistry) + { + _queueRegistry = queueRegistry; + _exchangeRegistry = exchangeRegistry; + + _logger.debug("AMQPFastProtocolHandler created"); + } + + protected AMQPFastProtocolHandler(AMQPFastProtocolHandler handler) + { + this(handler._queueRegistry, handler._exchangeRegistry); + } + + public void sessionCreated(IoSession protocolSession) throws Exception + { + SessionUtil.initialize(protocolSession); + final AMQCodecFactory codecFactory = new AMQCodecFactory(true); + + createSession(protocolSession, _queueRegistry, _exchangeRegistry, codecFactory); + _logger.info("Protocol session created"); + + final ProtocolCodecFilter pcf = new ProtocolCodecFilter(codecFactory); + + ConnectorConfiguration connectorConfig = ApplicationRegistry.getInstance(). + getConfiguredObject(ConnectorConfiguration.class); + if (connectorConfig.enableExecutorPool) + { + if (_useSSL) + { + protocolSession.getFilterChain().addAfter("AsynchronousReadFilter", "sslFilter", + new SSLFilter(BogusSSLContextFactory.getInstance(true))); + } + protocolSession.getFilterChain().addBefore("AsynchronousWriteFilter", "protocolFilter", pcf); + } + else + { + protocolSession.getFilterChain().addLast("protocolFilter", pcf); + } + } + + /** + * Separated into its own, protected, method to allow easier reuse + */ + protected void createSession(IoSession session, QueueRegistry queues, ExchangeRegistry exchanges, AMQCodecFactory codec) throws AMQException + { + new AMQMinaProtocolSession(session, queues, exchanges, codec); + } + + public void sessionOpened(IoSession protocolSession) throws Exception + { + _logger.info("Session opened"); + } + + public void sessionClosed(IoSession protocolSession) throws Exception + { + _logger.info("Protocol Session closed"); + final AMQProtocolSession amqProtocolSession = AMQMinaProtocolSession.getAMQProtocolSession(protocolSession); + amqProtocolSession.closeSession(); + } + + public void sessionIdle(IoSession session, IdleStatus status) throws Exception + { + _logger.debug("Protocol Session [" + this + "] idle: " + status); + if(IdleStatus.WRITER_IDLE.equals(status)) + { + //write heartbeat frame: + session.write(HeartbeatBody.FRAME); + } + else if(IdleStatus.READER_IDLE.equals(status)) + { + //failover: + throw new IOException("Timed out while waiting for heartbeat from peer."); + } + + } + + public void exceptionCaught(IoSession protocolSession, Throwable throwable) throws Exception + { + AMQProtocolSession session = AMQMinaProtocolSession.getAMQProtocolSession(protocolSession); + if (throwable instanceof AMQProtocolHeaderException) + { + /* Find last protocol version in protocol version list. Make sure last protocol version + listed in the build file (build-module.xml) is the latest version which will be returned + here. */ + int i = pv.length - 1; + protocolSession.write(new ProtocolInitiation(pv[i][PROTOCOL_MAJOR], pv[i][PROTOCOL_MINOR])); + protocolSession.close(); + _logger.error("Error in protocol initiation " + session + ": " + throwable.getMessage(), throwable); + } + else if(throwable instanceof IOException) + { + _logger.error("IOException caught in" + session + ", session closed implictly: " + throwable, throwable); + } + else + { + protocolSession.write(ConnectionCloseBody.createAMQFrame(0, 200, throwable.getMessage(), 0, 0)); + _logger.error("Exception caught in" + session + ", closing session explictly: " + throwable, throwable); + protocolSession.close(); + } + } + + /** + * Invoked when a message is received on a particular protocol session. Note that a + * protocol session is directly tied to a particular physical connection. + * @param protocolSession the protocol session that received the message + * @param message the message itself (i.e. a decoded frame) + * @throws Exception if the message cannot be processed + */ + public void messageReceived(IoSession protocolSession, Object message) throws Exception + { + final AMQProtocolSession amqProtocolSession = AMQMinaProtocolSession.getAMQProtocolSession(protocolSession); + + if (message instanceof AMQDataBlock) + { + amqProtocolSession.dataBlockReceived((AMQDataBlock) message); + } + else if (message instanceof ByteBuffer) + { + throw new IllegalStateException("Handed undecoded ByteBuffer buf = " + message); + } + else + { + throw new IllegalStateException("Handed unhandled message. message.class = " + message.getClass() + " message = " + message); + } + } + + /** + * Called after a message has been sent out on a particular protocol session + * @param protocolSession the protocol session (i.e. connection) on which this + * message was sent + * @param object the message (frame) that was encoded and sent + * @throws Exception if we want to indicate an error + */ + public void messageSent(IoSession protocolSession, Object object) throws Exception + { + if (_logger.isDebugEnabled()) + { + _logger.debug("Message sent: " + object); + } + } + + public boolean isUseSSL() + { + return _useSSL; + } + + public void setUseSSL(boolean useSSL) + { + _useSSL = useSSL; + } +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPProtocolProvider.java b/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPProtocolProvider.java new file mode 100644 index 0000000000..ff1316f704 --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQPProtocolProvider.java @@ -0,0 +1,53 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.protocol; + +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.registry.IApplicationRegistry; + +/** + * The protocol provide's role is to encapsulate the initialisation of the protocol handler. + * + * The protocol handler (see AMQPFastProtocolHandler class) handles protocol events + * such as connection closing or a frame being received. It can either do this directly + * or pass off to the protocol session in the cases where state information is required to + * deal with the event. + * + */ +public class AMQPProtocolProvider +{ + /** + * Handler for protocol events + */ + private AMQPFastProtocolHandler _handler; + + public AMQPProtocolProvider() + { + IApplicationRegistry registry = ApplicationRegistry.getInstance(); + _handler = new AMQPFastProtocolHandler(registry.getQueueRegistry(), + registry.getExchangeRegistry()); + } + + public AMQPFastProtocolHandler getHandler() + { + return _handler; + } +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java b/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java new file mode 100644 index 0000000000..acaf6b0d9b --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java @@ -0,0 +1,125 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.protocol; + +import org.apache.qpid.framing.AMQDataBlock; +import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.AMQException; + +import javax.security.sasl.SaslServer; + + +public interface AMQProtocolSession +{ + /** + * Called when a protocol data block is received + * @param message the data block that has been received + * @throws Exception if processing the datablock fails + */ + void dataBlockReceived(AMQDataBlock message) throws Exception; + + /** + * Write a datablock, encoding where necessary (e.g. into a sequence of bytes) + * @param frame the frame to be encoded and written + */ + void writeFrame(AMQDataBlock frame); + + /** + * Get the context key associated with this session. Context key is described + * in the AMQ protocol specification (RFC 6). + * @return the context key + */ + String getContextKey(); + + /** + * Set the context key associated with this session. Context key is described + * in the AMQ protocol specification (RFC 6). + * @param contextKey the context key + */ + void setContextKey(String contextKey); + + /** + * Get the channel for this session associated with the specified id. A channel + * id is unique per connection (i.e. per session). + * @param channelId the channel id which must be valid + * @return null if no channel exists, the channel otherwise + */ + AMQChannel getChannel(int channelId) throws AMQException; + + /** + * Associate a channel with this session. + * @param channel the channel to associate with this session. It is an error to + * associate the same channel with more than one session but this is not validated. + */ + void addChannel(AMQChannel channel); + + /** + * Close a specific channel. This will remove any resources used by the channel, including: + *
    • any queue subscriptions (this may in turn remove queues if they are auto delete
    • + *
    + * @param channelId id of the channel to close + * @throws org.apache.qpid.AMQException if an error occurs closing the channel + * @throws IllegalArgumentException if the channel id is not valid + */ + void closeChannel(int channelId) throws AMQException; + + /** + * Remove a channel from the session but do not close it. + * @param channelId + */ + void removeChannel(int channelId); + + /** + * Initialise heartbeats on the session. + * @param delay delay in seconds (not ms) + */ + void initHeartbeats(int delay); + + /** + * This must be called when the session is _closed in order to free up any resources + * managed by the session. + */ + void closeSession() throws AMQException; + + /** + * @return a key that uniquely identifies this session + */ + Object getKey(); + + /** + * Get the fully qualified domain name of the local address to which this session is bound. Since some servers + * may be bound to multiple addresses this could vary depending on the acceptor this session was created from. + * + * @return a String FQDN + */ + String getLocalFQDN(); + + /** + * @return the sasl server that can perform authentication for this session. + */ + SaslServer getSaslServer(); + + /** + * Set the sasl server that is to perform authentication for this session. + * @param saslServer + */ + void setSaslServer(SaslServer saslServer); +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/protocol/ExchangeInitialiser.java b/java/broker/src/main/java/org/apache/qpid/server/protocol/ExchangeInitialiser.java new file mode 100644 index 0000000000..d3ec70456f --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/protocol/ExchangeInitialiser.java @@ -0,0 +1,41 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.protocol; + +import org.apache.qpid.AMQException; +import org.apache.qpid.exchange.ExchangeDefaults; +import org.apache.qpid.server.exchange.ExchangeFactory; +import org.apache.qpid.server.exchange.ExchangeRegistry; + +public class ExchangeInitialiser +{ + public void initialise(ExchangeFactory factory, ExchangeRegistry registry) throws AMQException{ + define(registry, factory, ExchangeDefaults.DIRECT_EXCHANGE_NAME, ExchangeDefaults.DIRECT_EXCHANGE_CLASS); + define(registry, factory, ExchangeDefaults.TOPIC_EXCHANGE_NAME, ExchangeDefaults.TOPIC_EXCHANGE_CLASS); + define(registry, factory, ExchangeDefaults.HEADERS_EXCHANGE_NAME, ExchangeDefaults.HEADERS_EXCHANGE_CLASS); + } + + private void define(ExchangeRegistry r, ExchangeFactory f, + String name, String type) throws AMQException + { + r.registerExchange(f.createExchange(name, type, true, false, 0)); + } +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/protocol/HeartbeatConfig.java b/java/broker/src/main/java/org/apache/qpid/server/protocol/HeartbeatConfig.java new file mode 100644 index 0000000000..310deaaf55 --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/protocol/HeartbeatConfig.java @@ -0,0 +1,67 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.protocol; + +import org.apache.qpid.configuration.Configured; +import org.apache.qpid.server.registry.ApplicationRegistry; + +public class HeartbeatConfig +{ + @Configured(path = "heartbeat.delay", defaultValue = "5") + public int delay = 5;//in secs + @Configured(path = "heartbeat.timeoutFactor", defaultValue = "2.0") + public double timeoutFactor = 2; + + public double getTimeoutFactor() + { + return timeoutFactor; + } + + public void setTimeoutFactor(double timeoutFactor) + { + this.timeoutFactor = timeoutFactor; + } + + public int getDelay() + { + return delay; + } + + public void setDelay(int delay) + { + this.delay = delay; + } + + int getTimeout(int writeDelay) + { + return (int) (timeoutFactor * writeDelay); + } + + public static HeartbeatConfig getInstance() + { + return ApplicationRegistry.getInstance().getConfiguredObject(HeartbeatConfig.class); + } + + public String toString() + { + return "HeartBeatConfig{delay = " + delay + " timeoutFactor = " + timeoutFactor + "}"; + } +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/protocol/ManagedConnection.java b/java/broker/src/main/java/org/apache/qpid/server/protocol/ManagedConnection.java new file mode 100644 index 0000000000..889acd0142 --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/protocol/ManagedConnection.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.server.protocol; + +import org.apache.qpid.server.management.MBeanOperationParameter; +import org.apache.qpid.server.management.MBeanAttribute; +import org.apache.qpid.server.management.MBeanOperation; + +import javax.management.openmbean.TabularData; +import javax.management.JMException; +import javax.management.MBeanOperationInfo; +import java.util.Date; +import java.io.IOException; + +/** + * The management interface exposed to allow management of Connections. + * @author Bhupendra Bhardwaj + * @version 0.1 + */ +public interface ManagedConnection +{ + static final String TYPE = "Connection"; + + /** + * channel details of all the channels opened for this connection. + * @return general channel details + * @throws IOException + * @throws JMException + */ + @MBeanAttribute(name="Channels", + description="channel details of all the channels opened for this connection") + TabularData getChannels() throws IOException, JMException; + + /** + * Tells the last time, the IO operation was done. + * @return last IO time. + */ + @MBeanAttribute(name="LastIOTime", + description="The last time, the IO operation was done") + Date getLastIoTime(); + + /** + * Tells the remote address of this connection. + * @return remote address + */ + @MBeanAttribute(name="RemoteAddress", + description="The remote address of this connection") + String getRemoteAddress(); + + /** + * Tells the total number of bytes written till now. + * @return number of bytes written. + */ + @MBeanAttribute(name="WrittenBytes", + description="The total number of bytes written till now") + Long getWrittenBytes(); + + /** + * Tells the total number of bytes read till now. + * @return number of bytes read. + */ + @MBeanAttribute(name="ReadBytes", + description="The total number of bytes read till now") + Long getReadBytes(); + + /** + * Tells the maximum number of channels that can be opened using + * this connection. This is useful in setting notifications or + * taking required action is there are more channels being created. + * @return maximum number of channels allowed to be created. + */ + Long getMaximumNumberOfAllowedChannels(); + + /** + * Sets the maximum number of channels allowed to be created using + * this connection. + * @param value + */ + @MBeanAttribute(name="MaximumNumberOfAllowedChannels", + description="The maximum number of channels that can be opened using this connection") + void setMaximumNumberOfAllowedChannels(Long value); + + //********** Operations *****************// + + /** + * Closes all the related channels and unregisters this connection from managed objects. + */ + @MBeanOperation(name="closeConnection", + description="Closes this connection and all related channels", + impact= MBeanOperationInfo.ACTION) + void closeConnection() throws Exception; + + /** + * Unsubscribes the consumers and unregisters the channel from managed objects. + */ + @MBeanOperation(name="closeChannel", + description="Closes the channel with given channeld and" + + "connected consumers will be unsubscribed", + impact= MBeanOperationInfo.ACTION) + void closeChannel(@MBeanOperationParameter(name="channel Id", description="channel Id")int channelId) + throws Exception; + + /** + * Commits the transactions if the channel is transactional. + * @param channelId + * @throws JMException + */ + @MBeanOperation(name="commitTransaction", + description="Commits the transactions for given channelID, if the channel is transactional", + impact= MBeanOperationInfo.ACTION) + void commitTransactions(@MBeanOperationParameter(name="channel Id", description="channel Id")int channelId) throws JMException; + + /** + * Rollsback the transactions if the channel is transactional. + * @param channelId + * @throws JMException + */ + @MBeanOperation(name="rollbackTransactions", + description="Rollsback the transactions for given channelId, if the channel is transactional", + impact= MBeanOperationInfo.ACTION) + void rollbackTransactions(@MBeanOperationParameter(name="channel Id", description="channel Id")int channelId) throws JMException; +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java b/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java new file mode 100644 index 0000000000..8b6db5b53f --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java @@ -0,0 +1,368 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.queue; + +import org.apache.mina.common.ByteBuffer; +import org.apache.qpid.framing.*; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.store.MessageStore; +import org.apache.qpid.server.txn.TxnBuffer; +import org.apache.qpid.AMQException; + +import java.util.ArrayList; +import java.util.List; +import java.util.LinkedList; +import java.util.Set; +import java.util.HashSet; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * Combines the information that make up a deliverable message into a more manageable form. + */ +public class AMQMessage +{ + private final Set _tokens = new HashSet(); + + private AMQProtocolSession _publisher; + + private final BasicPublishBody _publishBody; + + private ContentHeaderBody _contentHeaderBody; + + private List _contentBodies; + + private boolean _redelivered; + + private final long _messageId; + + private final AtomicInteger _referenceCount = new AtomicInteger(1); + + /** + * Keeps a track of how many bytes we have received in body frames + */ + private long _bodyLengthReceived = 0; + + /** + * The message store in which this message is contained. + */ + private transient final MessageStore _store; + + /** + * For non transactional publishes, a message can be stored as + * soon as it is complete. For transactional messages it doesnt + * need to be stored until the transaction is committed. + */ + private boolean _storeWhenComplete; + + /** + * TxnBuffer for transactionally published messages + */ + private TxnBuffer _txnBuffer; + + /** + * Flag to indicate whether message has been delivered to a + * consumer. Used in implementing return functionality for + * messages published with the 'immediate' flag. + */ + private boolean _deliveredToConsumer; + + + public AMQMessage(MessageStore messageStore, BasicPublishBody publishBody) + { + this(messageStore, publishBody, true); + } + + public AMQMessage(MessageStore messageStore, BasicPublishBody publishBody, boolean storeWhenComplete) + { + _messageId = messageStore.getNewMessageId(); + _publishBody = publishBody; + _store = messageStore; + _contentBodies = new LinkedList(); + _storeWhenComplete = storeWhenComplete; + } + + public AMQMessage(MessageStore store, long messageId, BasicPublishBody publishBody, + ContentHeaderBody contentHeaderBody, List contentBodies) + throws AMQException + + { + _publishBody = publishBody; + _contentHeaderBody = contentHeaderBody; + _contentBodies = contentBodies; + _messageId = messageId; + _store = store; + storeMessage(); + } + + public AMQMessage(MessageStore store, BasicPublishBody publishBody, + ContentHeaderBody contentHeaderBody, List contentBodies) + throws AMQException + { + this(store, store.getNewMessageId(), publishBody, contentHeaderBody, contentBodies); + } + + protected AMQMessage(AMQMessage msg) throws AMQException + { + this(msg._store, msg._messageId, msg._publishBody, msg._contentHeaderBody, msg._contentBodies); + } + + public void storeMessage() throws AMQException + { + if (isPersistent()) + { + _store.put(this); + } + } + + public CompositeAMQDataBlock getDataBlock(ByteBuffer encodedDeliverBody, int channel) + { + AMQFrame[] allFrames = new AMQFrame[1 + _contentBodies.size()]; + + allFrames[0] = ContentHeaderBody.createAMQFrame(channel, _contentHeaderBody); + for (int i = 1; i < allFrames.length; i++) + { + allFrames[i] = ContentBody.createAMQFrame(channel, _contentBodies.get(i - 1)); + } + return new CompositeAMQDataBlock(encodedDeliverBody, allFrames); + } + + public CompositeAMQDataBlock getDataBlock(int channel, String consumerTag, long deliveryTag) + { + AMQFrame[] allFrames = new AMQFrame[2 + _contentBodies.size()]; + + allFrames[0] = BasicDeliverBody.createAMQFrame(channel, consumerTag, deliveryTag, _redelivered, + getExchangeName(), getRoutingKey()); + allFrames[1] = ContentHeaderBody.createAMQFrame(channel, _contentHeaderBody); + for (int i = 2; i < allFrames.length; i++) + { + allFrames[i] = ContentBody.createAMQFrame(channel, _contentBodies.get(i - 2)); + } + return new CompositeAMQDataBlock(allFrames); + } + + public List getPayload() + { + List payload = new ArrayList(2 + _contentBodies.size()); + payload.add(_publishBody); + payload.add(_contentHeaderBody); + payload.addAll(_contentBodies); + return payload; + } + + public BasicPublishBody getPublishBody() + { + return _publishBody; + } + + public ContentHeaderBody getContentHeaderBody() + { + return _contentHeaderBody; + } + + public void setContentHeaderBody(ContentHeaderBody contentHeaderBody) throws AMQException + { + _contentHeaderBody = contentHeaderBody; + if (_storeWhenComplete && isAllContentReceived()) + { + storeMessage(); + } + } + + public List getContentBodies() + { + return _contentBodies; + } + + public void setContentBodies(List contentBodies) + { + _contentBodies = contentBodies; + } + + public void addContentBodyFrame(ContentBody contentBody) throws AMQException + { + _contentBodies.add(contentBody); + _bodyLengthReceived += contentBody.getSize(); + if (_storeWhenComplete && isAllContentReceived()) + { + storeMessage(); + } + } + + public boolean isAllContentReceived() + { + return _bodyLengthReceived == _contentHeaderBody.bodySize; + } + + public boolean isRedelivered() + { + return _redelivered; + } + + String getExchangeName() + { + return _publishBody.exchange; + } + + String getRoutingKey() + { + return _publishBody.routingKey; + } + + boolean isImmediate() + { + return _publishBody.immediate; + } + + NoConsumersException getNoConsumersException(String queue) + { + return new NoConsumersException(queue, _publishBody, _contentHeaderBody, _contentBodies); + } + + void setRedelivered(boolean redelivered) + { + _redelivered = redelivered; + } + + public long getMessageId() + { + return _messageId; + } + + /** + * Threadsafe. Increment the reference count on the message. + */ + public void incrementReference() + { + _referenceCount.incrementAndGet(); + } + + /** + * Threadsafe. This will decrement the reference count and when it reaches zero will remove the message from the + * message store. + */ + public void decrementReference() throws MessageCleanupException + { + // note that the operation of decrementing the reference count and then removing the message does not + // have to be atomic since the ref count starts at 1 and the exchange itself decrements that after + // the message has been passed to all queues. i.e. we are + // not relying on the all the increments having taken place before the delivery manager decrements. + if (_referenceCount.decrementAndGet() == 0) + { + try + { + _store.removeMessage(_messageId); + } + catch(AMQException e) + { + //to maintain consistency, we revert the count + incrementReference(); + throw new MessageCleanupException(_messageId, e); + } + } + } + + public void setPublisher(AMQProtocolSession publisher) + { + _publisher = publisher; + } + + public AMQProtocolSession getPublisher() + { + return _publisher; + } + + public boolean checkToken(Object token) + { + if(_tokens.contains(token)) + { + return true; + } + else + { + _tokens.add(token); + return false; + } + } + + public void enqueue(AMQQueue queue) throws AMQException + { + //if the message is not persistent or the queue is not durable + //we will not need to recover the association and so do not + //need to record it + if(isPersistent() && queue.isDurable()) + { + _store.enqueueMessage(queue.getName(), _messageId); + } + } + + public void dequeue(AMQQueue queue) throws AMQException + { + //only record associations where both queue and message will survive + //a restart, so only need to remove association if this is the case + if(isPersistent() && queue.isDurable()) + { + _store.dequeueMessage(queue.getName(), _messageId); + } + } + + public boolean isPersistent() throws AMQException + { + if(_contentHeaderBody == null) + { + throw new AMQException("Cannot determine delivery mode of message. Content header not found."); + } + + //todo remove literal values to a constant file such as AMQConstants in common + return _contentHeaderBody.properties instanceof BasicContentHeaderProperties + &&((BasicContentHeaderProperties) _contentHeaderBody.properties).getDeliveryMode() == 2; + } + + public void setTxnBuffer(TxnBuffer buffer) + { + _txnBuffer = buffer; + } + + public TxnBuffer getTxnBuffer() + { + return _txnBuffer; + } + + /** + * Called to enforce the 'immediate' flag. + * @throws NoConsumersException if the message is marked for + * immediate delivery but has not been marked as delivered to a + * consumer + */ + public void checkDeliveredToConsumer() throws NoConsumersException{ + if(isImmediate() && !_deliveredToConsumer) + { + throw new NoConsumersException(_publishBody, _contentHeaderBody, _contentBodies); + } + } + + /** + * Called when this message is delivered to a consumer. (used to + * implement the 'immediate' flag functionality). + */ + public void setDeliveredToConsumer(){ + _deliveredToConsumer = true; + } +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java b/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java new file mode 100644 index 0000000000..f2f46d43dd --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java @@ -0,0 +1,867 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.queue; + +import org.apache.log4j.Logger; +import org.apache.mina.common.ByteBuffer; +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.BasicContentHeaderProperties; +import org.apache.qpid.framing.ContentBody; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.management.AMQManagedObject; +import org.apache.qpid.server.management.MBeanConstructor; +import org.apache.qpid.server.management.MBeanDescription; +import org.apache.qpid.server.management.Managable; +import org.apache.qpid.server.management.ManagedObject; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.txn.TxnBuffer; +import org.apache.qpid.server.txn.TxnOp; + +import javax.management.JMException; +import javax.management.MBeanException; +import javax.management.MBeanNotificationInfo; +import javax.management.NotCompliantMBeanException; +import javax.management.Notification; +import javax.management.monitor.MonitorNotification; +import javax.management.openmbean.*; +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.Executor; + +/** + * This is an AMQ Queue, and should not be confused with a JMS queue or any other abstraction like + * that. It is described fully in RFC 006. + */ +public class AMQQueue implements Managable +{ + private static final Logger _logger = Logger.getLogger(AMQQueue.class); + + private final String _name; + + /** + * null means shared + */ + private final String _owner; + + private final boolean _durable; + + /** + * If true, this queue is deleted when the last subscriber is removed + */ + private final boolean _autoDelete; + + /** + * Holds subscribers to the queue. + */ + private final SubscriptionSet _subscribers; + + private final SubscriptionFactory _subscriptionFactory; + + /** + * Manages message delivery. + */ + private final DeliveryManager _deliveryMgr; + + /** + * The queue registry with which this queue is registered. + */ + private final QueueRegistry _queueRegistry; + + /** + * Used to track bindings to exchanges so that on deletion they can easily + * be cancelled. + */ + private final ExchangeBindings _bindings = new ExchangeBindings(this); + + /** + * Executor on which asynchronous delivery will be carriedout where required + */ + private final Executor _asyncDelivery; + + private final AMQQueueMBean _managedObject; + + /** + * max allowed size of a single message(in KBytes). + */ + private long _maxAllowedMessageSize = 10000; // 10 MB + + /** + * max allowed number of messages on a queue. + */ + private Integer _maxAllowedMessageCount = 10000; + + /** + * max allowed size in KBytes for all the messages combined together in a queue. + */ + private long _queueDepth = 10000000; // 10 GB + + /** + * total messages received by the queue since startup. + */ + private long _totalMessagesReceived = 0; + + /** + * MBean class for AMQQueue. It implements all the management features exposed + * for an AMQQueue. + */ + @MBeanDescription("Management Interface for AMQQueue") + private final class AMQQueueMBean extends AMQManagedObject implements ManagedQueue + { + private String _queueName = null; + + // AMQ message attribute names + private String[] _msgAttributeNames = {"MessageId", + "Header", + "Size", + "Redelivered" + }; + // AMQ Message attribute descriptions. + private String[] _msgAttributeDescriptions = {"Message Id", + "Header", + "Message size in bytes", + "Redelivered" + }; + + private OpenType[] _msgAttributeTypes = new OpenType[4]; // AMQ message attribute types. + private String[] _msgAttributeIndex = {"MessageId"}; // Messages will be indexed according to the messageId. + private CompositeType _messageDataType = null; // Composite type for representing AMQ Message data. + private TabularType _messagelistDataType = null; // Datatype for representing AMQ messages list. + + + private CompositeType _msgContentType = null; // For message content + private String[] _msgContentAttributes = {"MessageId", + "MimeType", + "Encoding", + "Content" + }; + private String[] _msgContentDescriptions = {"Message Id", + "MimeType", + "Encoding", + "Message content" + }; + private OpenType[] _msgContentAttributeTypes = new OpenType[4]; + + + @MBeanConstructor("Creates an MBean exposing an AMQQueue.") + public AMQQueueMBean() throws NotCompliantMBeanException + { + super(ManagedQueue.class, ManagedQueue.TYPE); + init(); + } + + private void init() + { + _queueName = jmxEncode(new StringBuffer(_name), 0).toString(); + try + { + _msgContentAttributeTypes[0] = SimpleType.LONG; // For message id + _msgContentAttributeTypes[1] = SimpleType.STRING; // For MimeType + _msgContentAttributeTypes[2] = SimpleType.STRING; // For Encoding + _msgContentAttributeTypes[3] = new ArrayType(1, SimpleType.BYTE); // For message content + _msgContentType = new CompositeType("MessageContent", + "AMQ Message Content", + _msgContentAttributes, + _msgContentDescriptions, + _msgContentAttributeTypes); + + + _msgAttributeTypes[0] = SimpleType.LONG; // For message id + _msgAttributeTypes[1] = new ArrayType(1, SimpleType.STRING); // For header attributes + _msgAttributeTypes[2] = SimpleType.LONG; // For size + _msgAttributeTypes[3] = SimpleType.BOOLEAN; // For redelivered + + _messageDataType = new CompositeType("Message", + "AMQ Message", + _msgAttributeNames, + _msgAttributeDescriptions, + _msgAttributeTypes); + _messagelistDataType = new TabularType("Messages", + "List of messages", + _messageDataType, + _msgAttributeIndex); + } + catch (OpenDataException ex) + { + _logger.error("OpenDataTypes could not be created.", ex); + throw new RuntimeException(ex); + } + } + + public String getObjectInstanceName() + { + return _queueName; + } + + public String getName() + { + return _name; + } + + public boolean isDurable() + { + return _durable; + } + + public String getOwner() + { + return _owner; + } + + public boolean isAutoDelete() + { + return _autoDelete; + } + + public Integer getMessageCount() + { + return _deliveryMgr.getQueueMessageCount(); + } + + public Long getMaximumMessageSize() + { + return _maxAllowedMessageSize; + } + + public void setMaximumMessageSize(Long value) + { + _maxAllowedMessageSize = value; + } + + public Integer getConsumerCount() + { + return _subscribers.size(); + } + + public Integer getActiveConsumerCount() + { + return _subscribers.getWeight(); + } + + public Long getReceivedMessageCount() + { + return _totalMessagesReceived; + } + + public Integer getMaximumMessageCount() + { + return _maxAllowedMessageCount; + } + + public void setMaximumMessageCount(Integer value) + { + _maxAllowedMessageCount = value; + } + + public Long getQueueDepth() + { + return _queueDepth; + } + + // Sets the queue depth, the max queue size + public void setQueueDepth(Long value) + { + _queueDepth = value; + } + + // Returns the size of messages in the queue + public Long getQueueSize() + { + List list = _deliveryMgr.getMessages(); + if (list.size() == 0) + { + return 0l; + } + + long queueSize = 0; + for (AMQMessage message : list) + { + queueSize = queueSize + getMessageSize(message); + } + return new Long(Math.round(queueSize / 100)); + } + + // calculates the size of an AMQMessage + private long getMessageSize(AMQMessage msg) + { + if (msg == null) + { + return 0l; + } + + List cBodies = msg.getContentBodies(); + long messageSize = 0; + for (ContentBody body : cBodies) + { + if (body != null) + { + messageSize = messageSize + body.getSize(); + } + } + return messageSize; + } + + // Checks if there is any notification to be send to the listeners + private void checkForNotification(AMQMessage msg) + { + // Check for message count + Integer msgCount = getMessageCount(); + if (msgCount >= getMaximumMessageCount()) + { + notifyClients("MessageCount = " + msgCount + ", Queue has reached its size limit and is now full."); + } + + // Check for received message size + long messageSize = getMessageSize(msg); + if (messageSize >= getMaximumMessageSize()) + { + notifyClients("MessageSize = " + messageSize + ", Message size (MessageID=" + msg.getMessageId() + + ")is higher than the threshold value"); + } + + // Check for queue size in bytes + long queueSize = getQueueSize(); + if (queueSize >= getQueueDepth()) + { + notifyClients("QueueSize = " + queueSize + ", Queue size has reached the threshold value"); + } + } + + // Send the notification to the listeners + private void notifyClients(String notificationMsg) + { + Notification n = new Notification( + MonitorNotification.THRESHOLD_VALUE_EXCEEDED, + this, + ++_notificationSequenceNumber, + System.currentTimeMillis(), + notificationMsg); + + _broadcaster.sendNotification(n); + } + + public void deleteMessageFromTop() throws JMException + { + try + { + _deliveryMgr.removeAMessageFromTop(); + } + catch (AMQException ex) + { + throw new MBeanException(ex, ex.toString()); + } + } + + public void clearQueue() throws JMException + { + try + { + _deliveryMgr.clearAllMessages(); + } + catch (AMQException ex) + { + throw new MBeanException(ex, ex.toString()); + } + } + + public CompositeData viewMessageContent(long msgId) throws JMException + { + List list = _deliveryMgr.getMessages(); + CompositeData messageContent = null; + AMQMessage msg = null; + for (AMQMessage message : list) + { + if (message.getMessageId() == msgId) + { + msg = message; + break; + } + } + + if (msg != null) + { + // get message content + List cBodies = msg.getContentBodies(); + List msgContent = new ArrayList(); + for (ContentBody body : cBodies) + { + if (body.getSize() != 0) + { + ByteBuffer slice = body.payload.slice(); + for (int j = 0; j < slice.limit(); j++) + { + msgContent.add(slice.get()); + } + } + } + + // Create header attributes list + BasicContentHeaderProperties headerProperties = (BasicContentHeaderProperties)msg.getContentHeaderBody().properties; + String mimeType = headerProperties.getContentType(); + String encoding = headerProperties.getEncoding() == null ? "" : headerProperties.getEncoding(); + + Object[] itemValues = {msgId, mimeType, encoding, msgContent.toArray(new Byte[0])}; + messageContent = new CompositeDataSupport(_msgContentType, _msgContentAttributes, itemValues); + } + else + { + throw new JMException("AMQMessage with message id = " + msgId + " is not in the " + _queueName ); + } + + return messageContent; + } + + /** + * Returns the messages stored in this queue in tabular form. + * + * @param beginIndex + * @param endIndex + * @return AMQ messages in tabular form. + * @throws JMException + */ + public TabularData viewMessages(int beginIndex, int endIndex) throws JMException + { + if ((beginIndex > endIndex) || (beginIndex < 1)) + { + throw new JMException("FromIndex = " + beginIndex + ", ToIndex = " + endIndex + + "\nFromIndex should be greater than 0 and less than ToIndex"); + } + + List list = _deliveryMgr.getMessages(); + TabularDataSupport _messageList = new TabularDataSupport(_messagelistDataType); + + if (beginIndex > list.size()) + { + return _messageList; + } + endIndex = endIndex < list.size() ? endIndex : list.size(); + + for (int i = beginIndex; i <= endIndex; i++) + { + AMQMessage msg = list.get(i - 1); + long size = 0; + // get message content + List cBodies = msg.getContentBodies(); + for (ContentBody body : cBodies) + { + size = size + body.getSize(); + } + + // Create header attributes list + BasicContentHeaderProperties headerProperties = (BasicContentHeaderProperties)msg.getContentHeaderBody().properties; + List headerAttribsList = new ArrayList(); + headerAttribsList.add("App Id=" + headerProperties.getAppId()); + headerAttribsList.add("MimeType=" + headerProperties.getContentType()); + headerAttribsList.add("Correlation Id=" + headerProperties.getCorrelationId()); + headerAttribsList.add("Encoding=" + headerProperties.getEncoding()); + headerAttribsList.add(headerProperties.toString()); + + Object[] itemValues = {msg.getMessageId(), + headerAttribsList.toArray(new String[0]), + size, msg.isRedelivered()}; + + CompositeData messageData = new CompositeDataSupport(_messageDataType, + _msgAttributeNames, + itemValues); + _messageList.put(messageData); + } + + return _messageList; + } + + /** + * Creates all the notifications this MBean can send. + * + * @return Notifications broadcasted by this MBean. + */ + @Override + public MBeanNotificationInfo[] getNotificationInfo() + { + String[] notificationTypes = new String[] + {MonitorNotification.THRESHOLD_VALUE_EXCEEDED}; + String name = MonitorNotification.class.getName(); + String description = "An attribute of this MBean has reached threshold value"; + MBeanNotificationInfo info1 = new MBeanNotificationInfo(notificationTypes, + name, + description); + + return new MBeanNotificationInfo[]{info1}; + } + + } // End of AMQMBean class + + public AMQQueue(String name, boolean durable, String owner, + boolean autoDelete, QueueRegistry queueRegistry) + throws AMQException + { + this(name, durable, owner, autoDelete, queueRegistry, + AsyncDeliveryConfig.getAsyncDeliveryExecutor(), new SubscriptionImpl.Factory()); + } + + public AMQQueue(String name, boolean durable, String owner, + boolean autoDelete, QueueRegistry queueRegistry, SubscriptionFactory subscriptionFactory) + throws AMQException + { + this(name, durable, owner, autoDelete, queueRegistry, + AsyncDeliveryConfig.getAsyncDeliveryExecutor(), subscriptionFactory); + } + + public AMQQueue(String name, boolean durable, String owner, + boolean autoDelete, QueueRegistry queueRegistry, Executor asyncDelivery, + SubscriptionFactory subscriptionFactory) + throws AMQException + { + + this(name, durable, owner, autoDelete, queueRegistry, asyncDelivery, new SubscriptionSet(), subscriptionFactory); + } + + public AMQQueue(String name, boolean durable, String owner, + boolean autoDelete, QueueRegistry queueRegistry, Executor asyncDelivery) + throws AMQException + { + + this(name, durable, owner, autoDelete, queueRegistry, asyncDelivery, new SubscriptionSet(), + new SubscriptionImpl.Factory()); + } + + protected AMQQueue(String name, boolean durable, String owner, + boolean autoDelete, QueueRegistry queueRegistry, + SubscriptionSet subscribers, SubscriptionFactory subscriptionFactory) + throws AMQException + { + this(name, durable, owner, autoDelete, queueRegistry, + AsyncDeliveryConfig.getAsyncDeliveryExecutor(), subscribers, subscriptionFactory); + } + + protected AMQQueue(String name, boolean durable, String owner, + boolean autoDelete, QueueRegistry queueRegistry, + SubscriptionSet subscribers) + throws AMQException + { + this(name, durable, owner, autoDelete, queueRegistry, + AsyncDeliveryConfig.getAsyncDeliveryExecutor(), subscribers, new SubscriptionImpl.Factory()); + } + + protected AMQQueue(String name, boolean durable, String owner, + boolean autoDelete, QueueRegistry queueRegistry, + Executor asyncDelivery, SubscriptionSet subscribers, SubscriptionFactory subscriptionFactory) + throws AMQException + { + if (name == null) + { + throw new IllegalArgumentException("Queue name must not be null"); + } + if (queueRegistry == null) + { + throw new IllegalArgumentException("Queue registry must not be null"); + } + _name = name; + _durable = durable; + _owner = owner; + _autoDelete = autoDelete; + _queueRegistry = queueRegistry; + _asyncDelivery = asyncDelivery; + _managedObject = createMBean(); + _managedObject.register(); + _subscribers = subscribers; + _subscriptionFactory = subscriptionFactory; + + //fixme - Pick one. + if (Boolean.getBoolean("concurrentdeliverymanager")) + { + _logger.warn("Using ConcurrentDeliveryManager"); + _deliveryMgr = new ConcurrentDeliveryManager(_subscribers, this); + } + else + { + _logger.warn("Using SynchronizedDeliveryManager"); + _deliveryMgr = new SynchronizedDeliveryManager(_subscribers, this); + } + } + + private AMQQueueMBean createMBean() throws AMQException + { + try + { + return new AMQQueueMBean(); + } + catch (NotCompliantMBeanException ex) + { + throw new AMQException("AMQQueue MBean creation has failed.", ex); + } + } + + public String getName() + { + return _name; + } + + public boolean isShared() + { + return _owner == null; + } + + public boolean isDurable() + { + return _durable; + } + + public String getOwner() + { + return _owner; + } + + public boolean isAutoDelete() + { + return _autoDelete; + } + + public int getMessageCount() + { + return _deliveryMgr.getQueueMessageCount(); + } + + public ManagedObject getManagedObject() + { + return _managedObject; + } + + public void bind(String routingKey, Exchange exchange) + { + _bindings.addBinding(routingKey, exchange); + } + + public void registerProtocolSession(AMQProtocolSession ps, int channel, String consumerTag, boolean acks) + throws AMQException + { + debug("Registering protocol session {0} with channel {1} and consumer tag {2} with {3}", ps, channel, consumerTag, this); + + Subscription subscription = _subscriptionFactory.createSubscription(channel, ps, consumerTag, acks); + _subscribers.addSubscriber(subscription); + } + + public void unregisterProtocolSession(AMQProtocolSession ps, int channel, String consumerTag) throws AMQException + { + debug("Unregistering protocol session {0} with channel {1} and consumer tag {2} from {3}", ps, channel, consumerTag, + this); + + Subscription removedSubscription; + if ((removedSubscription = _subscribers.removeSubscriber(_subscriptionFactory.createSubscription(channel, + ps, + consumerTag))) + == null) + { + throw new AMQException("Protocol session with channel " + channel + " and consumer tag " + consumerTag + + " and protocol session key " + ps.getKey() + " not registered with queue " + this); + } + + // if we are eligible for auto deletion, unregister from the queue registry + if (_autoDelete && _subscribers.isEmpty()) + { + autodelete(); + // we need to manually fire the event to the removed subscription (which was the last one left for this + // queue. This is because the delete method uses the subscription set which has just been cleared + removedSubscription.queueDeleted(this); + } + } + + public int delete(boolean checkUnused, boolean checkEmpty) throws AMQException + { + if (checkUnused && !_subscribers.isEmpty()) + { + _logger.info("Will not delete " + this + " as it is in use."); + return 0; + } + else if (checkEmpty && _deliveryMgr.hasQueuedMessages()) + { + _logger.info("Will not delete " + this + " as it is not empty."); + return 0; + } + else + { + delete(); + return _deliveryMgr.getQueueMessageCount(); + } + } + + public void delete() throws AMQException + { + _subscribers.queueDeleted(this); + _bindings.deregister(); + _queueRegistry.unregisterQueue(_name); + _managedObject.unregister(); + } + + protected void autodelete() throws AMQException + { + debug("autodeleting {0}", this); + delete(); + } + + public void deliver(AMQMessage msg) throws AMQException + { + TxnBuffer buffer = msg.getTxnBuffer(); + if (buffer == null) + { + //non-transactional + record(msg); + process(msg); + } + else + { + buffer.enlist(new Deliver(msg)); + } + } + + private void record(AMQMessage msg) throws AMQException + { + msg.enqueue(this); + msg.incrementReference(); + } + + private void process(AMQMessage msg) throws FailedDequeueException + { + _deliveryMgr.deliver(getName(), msg); + try + { + msg.checkDeliveredToConsumer(); + updateReceivedMessageCount(msg); + } + catch (NoConsumersException e) + { + // as this message will be returned, it should be removed + // from the queue: + dequeue(msg); + } + } + + void dequeue(AMQMessage msg) throws FailedDequeueException + { + try + { + msg.dequeue(this); + msg.decrementReference(); + } + catch (MessageCleanupException e) + { + //Message was dequeued, but could notthen be deleted + //though it is no longer referenced. This should be very + //rare and can be detected and cleaned up on recovery or + //done through some form of manual intervention. + _logger.error(e, e); + } + catch (AMQException e) + { + throw new FailedDequeueException(_name, e); + } + } + + public void deliverAsync() + { + _deliveryMgr.processAsync(_asyncDelivery); + } + + protected SubscriptionManager getSubscribers() + { + return _subscribers; + } + + protected void updateReceivedMessageCount(AMQMessage msg) + { + _totalMessagesReceived++; + _managedObject.checkForNotification(msg); + } + + public boolean equals(Object o) + { + if (this == o) + { + return true; + } + if (o == null || getClass() != o.getClass()) + { + return false; + } + + final AMQQueue amqQueue = (AMQQueue) o; + + return (_name.equals(amqQueue._name)); + } + + public int hashCode() + { + return _name.hashCode(); + } + + public String toString() + { + return "Queue(" + _name + ")@" + System.identityHashCode(this); + } + + private void debug(String msg, Object... args) + { + if (_logger.isDebugEnabled()) + { + _logger.debug(MessageFormat.format(msg, args)); + } + } + + private class Deliver implements TxnOp + { + private final AMQMessage _msg; + + Deliver(AMQMessage msg) + { + _msg = msg; + } + + public void prepare() throws AMQException + { + //do the persistent part of the record() + _msg.enqueue(AMQQueue.this); + } + + public void undoPrepare() + { + } + + public void commit() + { + //do the memeory part of the record() + _msg.incrementReference(); + //then process the message + try + { + process(_msg); + } + catch (FailedDequeueException e) + { + //TODO: is there anything else we can do here? I think not... + _logger.error("Error during commit of a queue delivery: " + e, e); + } + } + + public void rollback() + { + } + } + +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/queue/AsyncDeliveryConfig.java b/java/broker/src/main/java/org/apache/qpid/server/queue/AsyncDeliveryConfig.java new file mode 100644 index 0000000000..ba60c9e003 --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/queue/AsyncDeliveryConfig.java @@ -0,0 +1,56 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.queue; + +import org.apache.qpid.configuration.Configured; +import org.apache.qpid.server.registry.ApplicationRegistry; + +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; + +public class AsyncDeliveryConfig +{ + private Executor _executor; + + @Configured(path = "delivery.poolsize", defaultValue = "0") + public int poolSize; + + public Executor getExecutor() + { + if (_executor == null) + { + if (poolSize > 0) + { + _executor = Executors.newFixedThreadPool(poolSize); + } + else + { + _executor = Executors.newCachedThreadPool(); + } + } + return _executor; + } + + public static Executor getAsyncDeliveryExecutor() + { + return ApplicationRegistry.getInstance().getConfiguredObject(AsyncDeliveryConfig.class).getExecutor(); + } +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentDeliveryManager.java b/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentDeliveryManager.java new file mode 100644 index 0000000000..dde76e5ba8 --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentDeliveryManager.java @@ -0,0 +1,348 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.queue; + +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.util.ConcurrentLinkedQueueAtomicSize; +import org.apache.qpid.configuration.Configured; +import org.apache.qpid.framing.ContentBody; +import org.apache.qpid.server.configuration.Configurator; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Queue; +import java.util.concurrent.Executor; +import java.util.concurrent.locks.ReentrantLock; +import java.util.concurrent.atomic.AtomicBoolean; + + +/** + * Manages delivery of messages on behalf of a queue + */ +public class ConcurrentDeliveryManager implements DeliveryManager +{ + private static final Logger _log = Logger.getLogger(ConcurrentDeliveryManager.class); + + @Configured(path = "advanced.compressBufferOnQueue", + defaultValue = "false") + public boolean compressBufferOnQueue; + /** + * Holds any queued messages + */ + private final Queue _messages = new ConcurrentLinkedQueueAtomicSize(); + //private int _messageCount; + /** + * Ensures that only one asynchronous task is running for this manager at + * any time. + */ + private final AtomicBoolean _processing = new AtomicBoolean(); + /** + * The subscriptions on the queue to whom messages are delivered + */ + private final SubscriptionManager _subscriptions; + + /** + * A reference to the queue we are delivering messages for. We need this to be able + * to pass the code that handles acknowledgements a handle on the queue. + */ + private final AMQQueue _queue; + + + /** + * Lock used to ensure that an channel that becomes unsuspended during the start of the queueing process is forced + * to wait till the first message is added to the queue. This will ensure that the _queue has messages to be delivered + * via the async thread. + *

    + * Lock is used to control access to hasQueuedMessages() and over the addition of messages to the queue. + */ + private ReentrantLock _lock = new ReentrantLock(); + + + ConcurrentDeliveryManager(SubscriptionManager subscriptions, AMQQueue queue) + { + + //Set values from configuration + Configurator.configure(this); + + if (compressBufferOnQueue) + { + _log.info("Compressing Buffers on queue."); + } + + _subscriptions = subscriptions; + _queue = queue; + } + + /** + * @return boolean if we are queueing + */ + private boolean queueing() + { + return hasQueuedMessages(); + } + + + /** + * @param msg to enqueue + * @return true if we are queue this message + */ + private boolean enqueue(AMQMessage msg) + { + if (msg.isImmediate()) + { + return false; + } + else + { + _lock.lock(); + try + { + if (queueing()) + { + return addMessageToQueue(msg); + } + else + { + return false; + } + } + finally + { + _lock.unlock(); + } + } + } + + private void startQueueing(AMQMessage msg) + { + if (!msg.isImmediate()) + { + addMessageToQueue(msg); + } + } + + private boolean addMessageToQueue(AMQMessage msg) + { + // Shrink the ContentBodies to their actual size to save memory. + if (compressBufferOnQueue) + { + Iterator it = msg.getContentBodies().iterator(); + while (it.hasNext()) + { + ContentBody cb = (ContentBody) it.next(); + cb.reduceBufferToFit(); + } + } + + _messages.offer(msg); + + return true; + } + + + public boolean hasQueuedMessages() + { + + _lock.lock(); + try + { + return !_messages.isEmpty(); + } + finally + { + _lock.unlock(); + } + + + } + + public int getQueueMessageCount() + { + return getMessageCount(); + } + + /** + * This is an EXPENSIVE opperation to perform with a ConcurrentLinkedQueue as it must run the queue to determine size. + * The ConcurrentLinkedQueueAtomicSize uses an AtomicInteger to record the number of elements on the queue. + * + * @return int the number of messages in the delivery queue. + */ + private int getMessageCount() + { + return _messages.size(); + } + + + public synchronized List getMessages() + { + return new ArrayList(_messages); + } + + public synchronized void removeAMessageFromTop() throws AMQException + { + AMQMessage msg = poll(); + if (msg != null) + { + msg.dequeue(_queue); + } + } + + public synchronized void clearAllMessages() throws AMQException + { + AMQMessage msg = poll(); + while (msg != null) + { + msg.dequeue(_queue); + msg = poll(); + } + } + + /** + * Only one thread should ever execute this method concurrently, but + * it can do so while other threads invoke deliver(). + */ + private void processQueue() + { + try + { + boolean hasSubscribers = _subscriptions.hasActiveSubscribers(); + AMQMessage message = peek(); + + //While we have messages to send and subscribers to send them to. + while (message != null && hasSubscribers) + { + // _log.debug("Have messages(" + _messages.size() + ") and subscribers"); + Subscription next = _subscriptions.nextSubscriber(message); + //FIXME Is there still not the chance that this subscribe could be suspended between here and the send? + + //We don't synchronize access to subscribers so need to re-check + if (next != null) + { + next.send(message, _queue); + poll(); + message = peek(); + } + else + { + hasSubscribers = false; + } + } + } + catch (FailedDequeueException e) + { + _log.error("Unable to deliver message as dequeue failed: " + e, e); + } + finally + { + _log.debug("End of processQueue: (" + getQueueMessageCount() + ")" + " subscribers:" + _subscriptions.hasActiveSubscribers()); + } + } + + private AMQMessage peek() + { + return _messages.peek(); + } + + private AMQMessage poll() + { + return _messages.poll(); + } + + Runner asyncDelivery = new Runner(); + + public void processAsync(Executor executor) + { + _log.debug("Processing Async. Queued:" + hasQueuedMessages() + "(" + getQueueMessageCount() + ")" + + " Active:" + _subscriptions.hasActiveSubscribers() + + " Processing:" + _processing.get()); + + if (hasQueuedMessages() && _subscriptions.hasActiveSubscribers()) + { + //are we already running? if so, don't re-run + if (_processing.compareAndSet(false, true)) + { + executor.execute(asyncDelivery); + } + } + } + + public void deliver(String name, AMQMessage msg) throws FailedDequeueException + { + // first check whether we are queueing, and enqueue if we are + if (!enqueue(msg)) + { + // not queueing so deliver message to 'next' subscriber + _lock.lock(); + try + { + Subscription s = _subscriptions.nextSubscriber(msg); + if (s == null) + { + if (!msg.isImmediate()) + { + // no subscribers yet so enter 'queueing' mode and queue this message + startQueueing(msg); + } + } + else + { + s.send(msg, _queue); + msg.setDeliveredToConsumer(); + } + } + finally + { + _lock.unlock(); + } + } + } + + private class Runner implements Runnable + { + public void run() + { + boolean running = true; + while (running) + { + processQueue(); + + //Check that messages have not been added since we did our last peek(); + // Synchronize with the thread that adds to the queue. + // If the queue is still empty then we can exit + _lock.lock(); + try + { + if (!(hasQueuedMessages() && _subscriptions.hasActiveSubscribers())) + { + running = false; + _processing.set(false); + } + } + finally + { + _lock.unlock(); + } + } + } + } +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/queue/DefaultQueueRegistry.java b/java/broker/src/main/java/org/apache/qpid/server/queue/DefaultQueueRegistry.java new file mode 100644 index 0000000000..3b73072e30 --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/queue/DefaultQueueRegistry.java @@ -0,0 +1,50 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.queue; + +import org.apache.qpid.AMQException; + +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.ConcurrentHashMap; + +public class DefaultQueueRegistry implements QueueRegistry +{ + private ConcurrentMap _queueMap = new ConcurrentHashMap(); + + public DefaultQueueRegistry() + { + } + + public void registerQueue(AMQQueue queue) throws AMQException + { + _queueMap.put(queue.getName(), queue); + } + + public void unregisterQueue(String name) throws AMQException + { + _queueMap.remove(name); + } + + public AMQQueue getQueue(String name) + { + return _queueMap.get(name); + } +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/queue/DeliveryManager.java b/java/broker/src/main/java/org/apache/qpid/server/queue/DeliveryManager.java new file mode 100644 index 0000000000..dadf86c1d8 --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/queue/DeliveryManager.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.server.queue; + +import org.apache.qpid.AMQException; + +import java.util.concurrent.Executor; +import java.util.List; + +interface DeliveryManager +{ + /** + * Determines whether there are queued messages. Sets _queueing to false if + * there are no queued messages. This needs to be atomic. + * + * @return true if there are queued messages + */ + boolean hasQueuedMessages(); + + /** + * This method should not be used to determin if there are messages in the queue. + * + * @return int The number of messages in the queue + * @use hasQueuedMessages() for all controls relating to having messages on the queue. + */ + int getQueueMessageCount(); + + /** + * Requests that the delivery manager start processing the queue asynchronously + * if there is work that can be done (i.e. there are messages queued up and + * subscribers that can receive them. + *

    + * This should be called when subscribers are added, but only after the consume-ok + * message has been returned as message delivery may start immediately. It should also + * be called after unsuspending a client. + *

    + * + * @param executor the executor on which the delivery should take place + */ + void processAsync(Executor executor); + + /** + * Handles message delivery. The delivery manager is always in one of two modes; + * it is either queueing messages for asynchronous delivery or delivering + * directly. + * + * @param name the name of the entity on whose behalf we are delivering the message + * @param msg the message to deliver + * @throws org.apache.qpid.server.queue.FailedDequeueException if the message could not be dequeued + */ + void deliver(String name, AMQMessage msg) throws FailedDequeueException; + + void removeAMessageFromTop() throws AMQException; + + void clearAllMessages() throws AMQException; + + List getMessages(); +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBindings.java b/java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBindings.java new file mode 100644 index 0000000000..684e312fa3 --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBindings.java @@ -0,0 +1,112 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.queue; + +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.AMQException; + +import java.util.List; +import java.util.HashSet; +import java.util.concurrent.CopyOnWriteArrayList; + +/** + * When a queue is deleted, it should be deregistered from any + * exchange it has been bound to. This class assists in this task, + * by keeping track of all bindings for a given queue. + */ +class ExchangeBindings +{ + static class ExchangeBinding + { + private final Exchange exchange; + private final String routingKey; + + ExchangeBinding(String routingKey, Exchange exchange) + { + this.routingKey = routingKey; + this.exchange = exchange; + } + + void unbind(AMQQueue queue) throws AMQException + { + exchange.deregisterQueue(routingKey, queue); + } + + public Exchange getExchange() + { + return exchange; + } + + public String getRoutingKey() + { + return routingKey; + } + + public int hashCode() + { + return exchange.hashCode() + routingKey.hashCode(); + } + + public boolean equals(Object o) + { + if (!(o instanceof ExchangeBinding)) return false; + ExchangeBinding eb = (ExchangeBinding) o; + return exchange.equals(eb.exchange) && routingKey.equals(eb.routingKey); + } + } + + private final List _bindings = new CopyOnWriteArrayList(); + private final AMQQueue _queue; + + ExchangeBindings(AMQQueue queue) + { + _queue = queue; + } + + /** + * Adds the specified binding to those being tracked. + * @param routingKey the routing key with which the queue whose bindings + * are being tracked by the instance has been bound to the exchange + * @param exchange the exchange bound to + */ + void addBinding(String routingKey, Exchange exchange) + { + _bindings.add(new ExchangeBinding(routingKey, exchange)); + } + + /** + * Deregisters this queue from any exchange it has been bound to + */ + void deregister() throws AMQException + { + //remove duplicates at this point + HashSet copy = new HashSet(_bindings); + for (ExchangeBinding b : copy) + { + b.unbind(_queue); + } + } + + List getExchangeBindings() + { + return _bindings; + } +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/queue/FailedDequeueException.java b/java/broker/src/main/java/org/apache/qpid/server/queue/FailedDequeueException.java new file mode 100644 index 0000000000..b74c49e6e1 --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/queue/FailedDequeueException.java @@ -0,0 +1,39 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.queue; + +import org.apache.qpid.AMQException; + +/** + * Signals that the dequeue of a message from a queue failed + */ +public class FailedDequeueException extends AMQException +{ + public FailedDequeueException(String queue) + { + super("Failed to dequeue message from " + queue); + } + + public FailedDequeueException(String queue, AMQException e) + { + super("Failed to dequeue message from " + queue, e); + } +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/queue/ManagedQueue.java b/java/broker/src/main/java/org/apache/qpid/server/queue/ManagedQueue.java new file mode 100644 index 0000000000..3a818cf31a --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/queue/ManagedQueue.java @@ -0,0 +1,220 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.queue; + +import org.apache.qpid.server.management.MBeanAttribute; +import org.apache.qpid.server.management.MBeanOperation; +import org.apache.qpid.server.management.MBeanOperationParameter; + +import javax.management.JMException; +import javax.management.MBeanOperationInfo; +import javax.management.openmbean.TabularData; +import javax.management.openmbean.CompositeData; +import java.io.IOException; + +/** + * The management interface exposed to allow management of a queue. + * @author Robert J. Greig + * @author Bhupendra Bhardwaj + * @version 0.1 + */ +public interface ManagedQueue +{ + static final String TYPE = "Queue"; + + /** + * Returns the Name of the ManagedQueue. + * @return the name of the managedQueue. + * @throws IOException + */ + @MBeanAttribute(name="Name", description = "Name of the " + TYPE) + String getName() throws IOException; + + /** + * Tells whether this ManagedQueue is durable or not. + * @return true if this ManagedQueue is a durable queue. + * @throws IOException + */ + @MBeanAttribute(name="Durable", description = "true if the AMQQueue is durable") + boolean isDurable() throws IOException; + + /** + * Tells the Owner of the ManagedQueue. + * @return the owner's name. + * @throws IOException + */ + @MBeanAttribute(name="Owner", description = "Owner") + String getOwner() throws IOException; + + /** + * Tells if the ManagedQueue is set to AutoDelete. + * @return true if the ManagedQueue is set to AutoDelete. + * @throws IOException + */ + @MBeanAttribute(name="AutoDelete", description = "true if the AMQQueue is AutoDelete") + boolean isAutoDelete() throws IOException; + + /** + * Total number of messages on the queue, which are yet to be delivered to the consumer(s). + * @return number of undelivered message in the Queue. + * @throws IOException + */ + @MBeanAttribute(name="MessageCount", + description = "Total number of undelivered messages on the queue") + Integer getMessageCount() throws IOException; + + /** + * Returns the maximum size of a message (in kbytes) allowed to be accepted by the + * ManagedQueue. This is useful in setting notifications or taking + * appropriate action, if the size of the message received is more than + * the allowed size. + * @return the maximum size of a message allowed to be aceepted by the + * ManagedQueue. + * @throws IOException + */ + Long getMaximumMessageSize() throws IOException; + + /** + * Sets the maximum size of the message (in kbytes) that is allowed to be + * accepted by the Queue. + * @param size maximum size of message. + * @throws IOException + */ + @MBeanAttribute(name="MaximumMessageSize", + description="Maximum size(KB) of a message allowed for this Queue") + void setMaximumMessageSize(Long size) throws IOException; + + /** + * Returns the total number of subscribers to the queue. + * @return the number of subscribers. + * @throws IOException + */ + @MBeanAttribute(name="ConsumerCount", description="The total number of subscribers to the queue") + Integer getConsumerCount() throws IOException; + + /** + * Returns the total number of active subscribers to the queue. + * @return the number of active subscribers + * @throws IOException + */ + @MBeanAttribute(name="ActiveConsumerCount", description="The total number of active subscribers to the queue") + Integer getActiveConsumerCount() throws IOException; + + /** + * Tells the total number of messages receieved by the queue since startup. + * @return total number of messages received. + * @throws IOException + */ + @MBeanAttribute(name="ReceivedMessageCount", + description="The total number of messages receieved by the queue since startup") + Long getReceivedMessageCount() throws IOException; + + /** + * Tells the maximum number of messages that can be stored in the queue. + * This is useful in setting the notifications or taking required + * action is the number of message increase this limit. + * @return maximum muber of message allowed to be stored in the queue. + * @throws IOException + */ + Integer getMaximumMessageCount() throws IOException; + + /** + * Sets the maximum number of messages allowed to be stored in the queue. + * @param value the maximum number of messages allowed to be stored in the queue. + * @throws IOException + */ + @MBeanAttribute(name="MaximumMessageCount", + description="The maximum number of messages allowed to be stored in the queue") + void setMaximumMessageCount(Integer value) throws IOException; + + /** + * Size of messages in the queue + * @return + * @throws IOException + */ + @MBeanAttribute(name="QueueSize", description="Size of messages(KB) in the queue") + Long getQueueSize() throws IOException; + + /** + * Tells the maximum size of all the messages combined together, + * that can be stored in the queue. This is useful for setting notifications + * or taking required action if the size of messages stored in the queue + * increases over this limit. + * @return maximum size of the all the messages allowed for the queue. + * @throws IOException + */ + Long getQueueDepth() throws IOException; + + /** + * Sets the maximum size of all the messages together, that can be stored + * in the queue. + * @param value + * @throws IOException + */ + @MBeanAttribute(name="QueueDepth", + description="The size(KB) of all the messages together, that can be stored in the queue") + void setQueueDepth(Long value) throws IOException; + + + + //********** Operations *****************// + + + /** + * Returns a subset of all the messages stored in the queue. The messages + * are returned based on the given index numbers. + * @param fromIndex + * @param toIndex + * @return + * @throws IOException + * @throws JMException + */ + @MBeanOperation(name="viewMessages", + description="shows messages in this queue with given indexes. eg. from index 1 - 100") + TabularData viewMessages(@MBeanOperationParameter(name="from index", description="from index")int fromIndex, + @MBeanOperationParameter(name="to index", description="to index")int toIndex) + throws IOException, JMException; + + /** + * Deletes the first message from top. + * @throws IOException + * @throws JMException + */ + @MBeanOperation(name="deleteMessageFromTop", + description="Deletes the first message from top", + impact= MBeanOperationInfo.ACTION) + void deleteMessageFromTop() throws IOException, JMException; + + /** + * Clears the queue by deleting all the undelivered messages from the queue. + * @throws IOException + * @throws JMException + */ + @MBeanOperation(name="clearQueue", + description="Clears the queue by deleting all the undelivered messages from the queue", + impact= MBeanOperationInfo.ACTION) + void clearQueue() throws IOException, JMException; + + @MBeanOperation(name="viewMessageContent", + description="Returns the message content along with MimeType and Encoding") + CompositeData viewMessageContent(@MBeanOperationParameter(name="Message Id", description="Message Id")long messageId) + throws IOException, JMException; +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/queue/MessageCleanupException.java b/java/broker/src/main/java/org/apache/qpid/server/queue/MessageCleanupException.java new file mode 100644 index 0000000000..bfe0a0ecf1 --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/queue/MessageCleanupException.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.server.queue; + +import org.apache.qpid.AMQException; + +/** + * Signals that the removal of a message once its refcount reached + * zero failed. + */ +public class MessageCleanupException extends AMQException +{ + public MessageCleanupException(long messageId, AMQException e) + { + super("Failed to cleanup message with id " + messageId, e); + } +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/queue/NoConsumersException.java b/java/broker/src/main/java/org/apache/qpid/server/queue/NoConsumersException.java new file mode 100644 index 0000000000..2d37b806f6 --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/queue/NoConsumersException.java @@ -0,0 +1,57 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.queue; + +import org.apache.qpid.server.RequiredDeliveryException; +import org.apache.qpid.framing.ContentHeaderBody; +import org.apache.qpid.framing.ContentBody; +import org.apache.qpid.framing.BasicPublishBody; +import org.apache.qpid.protocol.AMQConstant; + +import java.util.List; + +/** + * Signals that no consumers exist for a message at a given point in time. + * Used if a message has immediate=true and there are no consumers registered + * with the queue. + */ +public class NoConsumersException extends RequiredDeliveryException +{ + public NoConsumersException(String queue, + BasicPublishBody publishBody, + ContentHeaderBody contentHeaderBody, + List contentBodies) + { + super("Immediate delivery to " + queue + " is not possible.", publishBody, contentHeaderBody, contentBodies); + } + + public NoConsumersException(BasicPublishBody publishBody, + ContentHeaderBody contentHeaderBody, + List contentBodies) + { + super("Immediate delivery is not possible.", publishBody, contentHeaderBody, contentBodies); + } + + public int getReplyCode() + { + return AMQConstant.NO_CONSUMERS.getCode(); + } +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/queue/QueueRegistry.java b/java/broker/src/main/java/org/apache/qpid/server/queue/QueueRegistry.java new file mode 100644 index 0000000000..c83f17b98c --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/queue/QueueRegistry.java @@ -0,0 +1,33 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.queue; + +import org.apache.qpid.AMQException; + + +public interface QueueRegistry +{ + void registerQueue(AMQQueue queue) throws AMQException; + + void unregisterQueue(String name) throws AMQException; + + AMQQueue getQueue(String name); +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/queue/Subscription.java b/java/broker/src/main/java/org/apache/qpid/server/queue/Subscription.java new file mode 100644 index 0000000000..dfc16a7c71 --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/queue/Subscription.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.server.queue; + +import org.apache.qpid.AMQException; + +public interface Subscription +{ + void send(AMQMessage msg, AMQQueue queue) throws FailedDequeueException; + + boolean isSuspended(); + + void queueDeleted(AMQQueue queue); +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionFactory.java b/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionFactory.java new file mode 100644 index 0000000000..0fd44e4fbc --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionFactory.java @@ -0,0 +1,40 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.queue; + +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.AMQException; + +/** + * Allows the customisation of the creation of a subscription. This is typically done within an AMQQueue. This + * factory primarily assists testing although in future more sophisticated subscribers may need a different + * subscription implementation. + * + * @see org.apache.qpid.server.queue.AMQQueue + */ +public interface SubscriptionFactory +{ + Subscription createSubscription(int channel, AMQProtocolSession protocolSession, String consumerTag, boolean acks) + throws AMQException; + + Subscription createSubscription(int channel, AMQProtocolSession protocolSession,String consumerTag) + throws AMQException; +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java b/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java new file mode 100644 index 0000000000..5cad28b80d --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java @@ -0,0 +1,191 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.queue; + +import org.apache.log4j.Logger; +import org.apache.mina.common.ByteBuffer; +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQDataBlock; +import org.apache.qpid.framing.AMQFrame; +import org.apache.qpid.framing.BasicDeliverBody; +import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.protocol.AMQProtocolSession; + +/** + * Encapsulation of a supscription to a queue. + *

    + * Ties together the protocol session of a subscriber, the consumer tag that + * was given out by the broker and the channel id. + *

    + */ +public class SubscriptionImpl implements Subscription +{ + private static final Logger _logger = Logger.getLogger(SubscriptionImpl.class); + + public final AMQChannel channel; + + public final AMQProtocolSession protocolSession; + + public final String consumerTag; + + private final Object sessionKey; + + /** + * True if messages need to be acknowledged + */ + private final boolean _acks; + + public static class Factory implements SubscriptionFactory + { + public SubscriptionImpl createSubscription(int channel, AMQProtocolSession protocolSession, String consumerTag, boolean acks) + throws AMQException + { + return new SubscriptionImpl(channel, protocolSession, consumerTag, acks); + } + + public SubscriptionImpl createSubscription(int channel, AMQProtocolSession protocolSession, String consumerTag) + throws AMQException + { + return new SubscriptionImpl(channel, protocolSession, consumerTag); + } + } + + public SubscriptionImpl(int channelId, AMQProtocolSession protocolSession, + String consumerTag, boolean acks) + throws AMQException + { + AMQChannel channel = protocolSession.getChannel(channelId); + if (channel == null) + { + throw new NullPointerException("channel not found in protocol session"); + } + + this.channel = channel; + this.protocolSession = protocolSession; + this.consumerTag = consumerTag; + sessionKey = protocolSession.getKey(); + _acks = acks; + } + + public SubscriptionImpl(int channel, AMQProtocolSession protocolSession, + String consumerTag) + throws AMQException + { + this(channel, protocolSession, consumerTag, false); + } + + public boolean equals(Object o) + { + return (o instanceof SubscriptionImpl) && equals((SubscriptionImpl) o); + } + + /** + * Equality holds if the session matches and the channel and consumer tag are the same. + */ + private boolean equals(SubscriptionImpl psc) + { + return sessionKey.equals(psc.sessionKey) + && psc.channel == channel + && psc.consumerTag.equals(consumerTag); + } + + public int hashCode() + { + return sessionKey.hashCode(); + } + + public String toString() + { + return "[channel=" + channel + ", consumerTag=" + consumerTag + ", session=" + protocolSession.getKey() + "]"; + } + + /** + * This method can be called by each of the publisher threads. + * As a result all changes to the channel object must be thread safe. + * + * @param msg + * @param queue + * @throws AMQException + */ + public void send(AMQMessage msg, AMQQueue queue) throws FailedDequeueException + { + if (msg != null) + { + // if we do not need to wait for client acknowledgements + // we can decrement the reference count immediately. + + // By doing this _before_ the send we ensure that it + // doesn't get sent if it can't be dequeued, preventing + // duplicate delivery on recovery. + + // The send may of course still fail, in which case, as + // the message is unacked, it will be lost. + if (!_acks) + { + queue.dequeue(msg); + } + synchronized(channel) + { + long deliveryTag = channel.getNextDeliveryTag(); + + if (_acks) + { + channel.addUnacknowledgedMessage(msg, deliveryTag, consumerTag, queue); + } + + ByteBuffer deliver = createEncodedDeliverFrame(deliveryTag, msg.getRoutingKey(), msg.getExchangeName()); + AMQDataBlock frame = msg.getDataBlock(deliver, channel.getChannelId()); + + protocolSession.writeFrame(frame); + } + } + else + { + _logger.error("Attempt to send Null message", new NullPointerException()); + } + } + + public boolean isSuspended() + { + return channel.isSuspended(); + } + + /** + * Callback indicating that a queue has been deleted. + * + * @param queue + */ + public void queueDeleted(AMQQueue queue) + { + channel.queueDeleted(queue); + } + + private ByteBuffer createEncodedDeliverFrame(long deliveryTag, String routingKey, String exchange) + { + AMQFrame deliverFrame = BasicDeliverBody.createAMQFrame(channel.getChannelId(), consumerTag, + deliveryTag, false, exchange, + routingKey); + ByteBuffer buf = ByteBuffer.allocate((int) deliverFrame.getSize()); // XXX: Could cast be a problem? + deliverFrame.writePayload(buf); + buf.flip(); + return buf; + } +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionManager.java b/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionManager.java new file mode 100644 index 0000000000..353b461c8d --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionManager.java @@ -0,0 +1,31 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.queue; + +/** + * Abstraction of actor that will determine the subscriber to whom + * a message will be sent. + */ +public interface SubscriptionManager +{ + public boolean hasActiveSubscribers(); + public Subscription nextSubscriber(AMQMessage msg); +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionSet.java b/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionSet.java new file mode 100644 index 0000000000..7cc3f5f719 --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionSet.java @@ -0,0 +1,183 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.queue; + +import org.apache.log4j.Logger; +import java.util.List; +import java.util.ListIterator; +import java.util.concurrent.CopyOnWriteArrayList; + +/** + * Holds a set of subscriptions for a queue and manages the round + * robin-ing of deliver etc. + */ +class SubscriptionSet implements WeightedSubscriptionManager +{ + private static final Logger _log = Logger.getLogger(SubscriptionSet.class); + + /** + * List of registered subscribers + */ + private List _subscriptions = new CopyOnWriteArrayList(); + + /** + * Used to control the round robin delivery of content + */ + private int _currentSubscriber; + + /** + * Accessor for unit tests. + */ + int getCurrentSubscriber() + { + return _currentSubscriber; + } + + public void addSubscriber(Subscription subscription) + { + _subscriptions.add(subscription); + } + + /** + * Remove the subscription, returning it if it was found + * @param subscription + * @return null if no match was found + */ + public Subscription removeSubscriber(Subscription subscription) + { + boolean isRemoved = _subscriptions.remove(subscription); // TODO: possibly need O(1) operation here. + if (isRemoved) + { + return subscription; + } + else + { + debugDumpSubscription(subscription); + return null; + } + } + + private void debugDumpSubscription(Subscription subscription) + { + if (_log.isDebugEnabled()) + { + _log.debug("Subscription " + subscription + " not found. Dumping subscriptions:"); + for (Subscription s : _subscriptions) + { + _log.debug("Subscription: " + s); + } + _log.debug("Subscription dump complete"); + } + } + + /** + * Return the next unsuspended subscription or null if not found. + * + * Performance note: + * This method can scan all items twice when looking for a subscription that is not + * suspended. The worst case occcurs when all subscriptions are suspended. However, it is does this + * without synchronisation and subscriptions may be added and removed concurrently. Also note that because of + * race conditions and when subscriptions are removed between calls to nextSubscriber, the + * IndexOutOfBoundsException also causes the scan to start at the beginning. + */ + public Subscription nextSubscriber(AMQMessage msg) + { + if (_subscriptions.isEmpty()) + { + return null; + } + + try { + final Subscription result = nextSubscriber(); + if (result == null) { + _currentSubscriber = 0; + return nextSubscriber(); + } else { + return result; + } + } catch (IndexOutOfBoundsException e) { + _currentSubscriber = 0; + return nextSubscriber(); + } + } + + private Subscription nextSubscriber() + { + final ListIterator iterator = _subscriptions.listIterator(_currentSubscriber); + while (iterator.hasNext()) { + Subscription subscription = iterator.next(); + ++_currentSubscriber; + subscriberScanned(); + if (!subscription.isSuspended()) { + return subscription; + } + } + return null; + } + + /** + * Overridden in test classes. + */ + protected void subscriberScanned() + { + } + + public boolean isEmpty() + { + return _subscriptions.isEmpty(); + } + + public boolean hasActiveSubscribers() + { + for (Subscription s : _subscriptions) + { + if (!s.isSuspended()) return true; + } + return false; + } + + public int getWeight() + { + int count = 0; + for (Subscription s : _subscriptions) + { + if (!s.isSuspended()) count++; + } + return count; + } + + /** + * Notification that a queue has been deleted. This is called so that the subscription can inform the + * channel, which in turn can update its list of unacknowledged messages. + * @param queue + */ + public void queueDeleted(AMQQueue queue) + { + for (Subscription s : _subscriptions) + { + s.queueDeleted(queue); + } + } + + int size() { + return _subscriptions.size(); + } +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/queue/SynchronizedDeliveryManager.java b/java/broker/src/main/java/org/apache/qpid/server/queue/SynchronizedDeliveryManager.java new file mode 100644 index 0000000000..d2e53717af --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/queue/SynchronizedDeliveryManager.java @@ -0,0 +1,255 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.queue; + +import org.apache.qpid.AMQException; +import org.apache.log4j.Logger; + +import java.util.LinkedList; +import java.util.Queue; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.Executor; +import java.util.concurrent.atomic.AtomicBoolean; + +/** + * Manages delivery of messages on behalf of a queue + */ +class SynchronizedDeliveryManager implements DeliveryManager +{ + private static final Logger _log = Logger.getLogger(ConcurrentDeliveryManager.class); + + /** + * Holds any queued messages + */ + private final Queue _messages = new LinkedList(); + /** + * Ensures that only one asynchronous task is running for this manager at + * any time. + */ + private final AtomicBoolean _processing = new AtomicBoolean(); + /** + * The subscriptions on the queue to whom messages are delivered + */ + private final SubscriptionManager _subscriptions; + + /** + * An indication of the mode we are in. If this is true then messages are + * being queued up in _messages for asynchronous delivery. If it is false + * then messages can be delivered directly as they come in. + */ + private volatile boolean _queueing; + + /** + * A reference to the queue we are delivering messages for. We need this to be able + * to pass the code that handles acknowledgements a handle on the queue. + */ + private final AMQQueue _queue; + + SynchronizedDeliveryManager(SubscriptionManager subscriptions, AMQQueue queue) + { + _subscriptions = subscriptions; + _queue = queue; + } + + private synchronized boolean enqueue(AMQMessage msg) + { + if (msg.isImmediate()) + { + return false; + } + else + { + if (_queueing) + { + _messages.offer(msg); + return true; + } + else + { + return false; + } + } + } + + private synchronized void startQueueing(AMQMessage msg) + { + _queueing = true; + enqueue(msg); + } + + /** + * Determines whether there are queued messages. Sets _queueing to false if + * there are no queued messages. This needs to be atomic. + * + * @return true if there are queued messages + */ + public synchronized boolean hasQueuedMessages() + { + boolean empty = _messages.isEmpty(); + if (empty) + { + _queueing = false; + } + return !empty; + } + + public synchronized int getQueueMessageCount() + { + return _messages.size(); + } + + public synchronized List getMessages() + { + return new ArrayList(_messages); + } + + public synchronized void removeAMessageFromTop() throws AMQException + { + AMQMessage msg = poll(); + if (msg != null) + { + msg.dequeue(_queue); + } + } + + public synchronized void clearAllMessages() throws AMQException + { + AMQMessage msg = poll(); + while (msg != null) + { + msg.dequeue(_queue); + msg = poll(); + } + } + + /** + * Only one thread should ever execute this method concurrently, but + * it can do so while other threads invoke deliver(). + */ + private void processQueue() + { + try + { + boolean hasSubscribers = _subscriptions.hasActiveSubscribers(); + while (hasQueuedMessages() && hasSubscribers) + { + Subscription next = _subscriptions.nextSubscriber(peek()); + //We don't synchronize access to subscribers so need to re-check + if (next != null) + { + try + { + next.send(poll(), _queue); + } + catch (AMQException e) + { + _log.error("Unable to deliver message: " + e, e); + } + } + else + { + hasSubscribers = false; + } + } + } + finally + { + _processing.set(false); + } + } + + private synchronized AMQMessage peek() + { + return _messages.peek(); + } + + private synchronized AMQMessage poll() + { + return _messages.poll(); + } + + /** + * Requests that the delivery manager start processing the queue asynchronously + * if there is work that can be done (i.e. there are messages queued up and + * subscribers that can receive them. + *

    + * This should be called when subscribers are added, but only after the consume-ok + * message has been returned as message delivery may start immediately. It should also + * be called after unsuspending a client. + *

    + * + * @param executor the executor on which the delivery should take place + */ + public void processAsync(Executor executor) + { + if (hasQueuedMessages() && _subscriptions.hasActiveSubscribers()) + { + //are we already running? if so, don't re-run + if (_processing.compareAndSet(false, true)) + { + executor.execute(new Runner()); + } + } + } + + /** + * Handles message delivery. The delivery manager is always in one of two modes; + * it is either queueing messages for asynchronous delivery or delivering + * directly. + * + * @param name the name of the entity on whose behalf we are delivering the message + * @param msg the message to deliver + * @throws NoConsumersException if there are no active subscribers to deliver + * the message to + */ + public void deliver(String name, AMQMessage msg) throws FailedDequeueException + { + // first check whether we are queueing, and enqueue if we are + if (!enqueue(msg)) + { + synchronized(this) + { + // not queueing so deliver message to 'next' subscriber + Subscription s = _subscriptions.nextSubscriber(msg); + if (s == null) + { + // no subscribers yet so enter 'queueing' mode and queue this message + startQueueing(msg); + } + else + { + s.send(msg, _queue); + msg.setDeliveredToConsumer(); + } + } + } + + } + + private class Runner implements Runnable + { + public void run() + { + processQueue(); + } + } +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/queue/WeightedSubscriptionManager.java b/java/broker/src/main/java/org/apache/qpid/server/queue/WeightedSubscriptionManager.java new file mode 100644 index 0000000000..6c71571807 --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/queue/WeightedSubscriptionManager.java @@ -0,0 +1,26 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.queue; + +public interface WeightedSubscriptionManager extends SubscriptionManager +{ + public int getWeight(); +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java b/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java new file mode 100644 index 0000000000..48331843e5 --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java @@ -0,0 +1,200 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.registry; + +import org.apache.commons.configuration.Configuration; +import org.apache.log4j.Logger; +import org.apache.qpid.server.configuration.Configurator; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +/** + * An abstract application registry that provides access to configuration information and handles the + * construction and caching of configurable objects. + *

    + * Subclasses should handle the construction of the "registered objects" such as the exchange registry. + */ +public abstract class ApplicationRegistry implements IApplicationRegistry +{ + private static final Logger _logger = Logger.getLogger(ApplicationRegistry.class); + + private static Map _instanceMap = new HashMap(); + + private final Map, Object> _configuredObjects = new HashMap, Object>(); + + protected final Configuration _configuration; + + public static final int DEFAULT_INSTANCE = 1; + public static final String DEFAULT_APPLICATION_REGISTRY = "org.apache.qpid.server.util.NullApplicationRegistry"; + public static String _APPLICATION_REGISTRY = DEFAULT_APPLICATION_REGISTRY; + + static + { + Runtime.getRuntime().addShutdownHook(new Thread(new ShutdownService())); + } + + private static class ShutdownService implements Runnable + { + public void run() + { + _logger.info("Shutting down application registries..."); + try + { + synchronized (ApplicationRegistry.class) + { + Iterator keyIterator = _instanceMap.keySet().iterator(); + + while (keyIterator.hasNext()) + { + int key = (Integer) keyIterator.next(); + IApplicationRegistry instance = (IApplicationRegistry) _instanceMap.get(key); + + if ((instance != null)) + { + if (instance.getMessageStore() != null) + { + instance.getMessageStore().close(); + } + } + } + } + } + catch (Exception e) + { + _logger.error("Error shutting down message store: " + e, e); + } + } + } + + public static void initialise(IApplicationRegistry instance) throws Exception + { + initialise(instance, DEFAULT_INSTANCE); + } + + public static void initialise(IApplicationRegistry instance, int instanceID) throws Exception + { + if (instance != null) + { + _logger.info("Initialising Application Registry:" + instanceID); + _instanceMap.put(instanceID, instance); + + try + { + instance.initialise(); + } + catch (Exception e) + { + _instanceMap.remove(instanceID); + throw e; + } + } + else + { + remove(instanceID); + } + } + + public static void remove(int instanceID) + { + try + { + ((IApplicationRegistry) _instanceMap.get(instanceID)).getMessageStore().close(); + } + catch (Exception e) + { + + } + finally + { + _instanceMap.remove(instanceID); + } + } + + + protected ApplicationRegistry(Configuration configuration) + { + _configuration = configuration; + } + + public static IApplicationRegistry getInstance() + { + return getInstance(DEFAULT_INSTANCE); + } + + public static IApplicationRegistry getInstance(int instanceID) + { + IApplicationRegistry instance = (IApplicationRegistry) _instanceMap.get(instanceID); + + if (instance == null) + { + try + { + _logger.info("Creating DEFAULT_APPLICATION_REGISTRY: " + _APPLICATION_REGISTRY + " : Instance:" + instanceID); + IApplicationRegistry registry = (IApplicationRegistry) Class.forName(_APPLICATION_REGISTRY).getConstructor((Class[]) null).newInstance((Object[]) null); + ApplicationRegistry.initialise(registry, instanceID); + _logger.info("Initialised Application Registry:" + instanceID); + return registry; + } + catch (Exception e) + { + _logger.error("Error configuring application: " + e, e); + //throw new AMQBrokerCreationException(instanceID, "Unable to create Application Registry instance " + instanceID); + throw new RuntimeException("Unable to create Application Registry"); + } + } + else + { + return instance; + } + } + + public Configuration getConfiguration() + { + return _configuration; + } + + public T getConfiguredObject(Class instanceType) + { + T instance = (T) _configuredObjects.get(instanceType); + if (instance == null) + { + try + { + instance = instanceType.newInstance(); + } + catch (Exception e) + { + _logger.error("Unable to instantiate configuration class " + instanceType + " - ensure it has a public default constructor"); + throw new IllegalArgumentException("Unable to instantiate configuration class " + instanceType + " - ensure it has a public default constructor"); + } + Configurator.configure(instance); + _configuredObjects.put(instanceType, instance); + } + return instance; + } + + public static void setDefaultApplicationRegistry(String clazz) + { + _APPLICATION_REGISTRY = clazz; + } +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java b/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java new file mode 100644 index 0000000000..1eb490d6fb --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java @@ -0,0 +1,158 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.registry; + +import org.apache.commons.configuration.CompositeConfiguration; +import org.apache.commons.configuration.Configuration; +import org.apache.commons.configuration.ConfigurationException; +import org.apache.commons.configuration.SystemConfiguration; +import org.apache.commons.configuration.XMLConfiguration; +import org.apache.qpid.server.exchange.DefaultExchangeFactory; +import org.apache.qpid.server.exchange.DefaultExchangeRegistry; +import org.apache.qpid.server.exchange.ExchangeFactory; +import org.apache.qpid.server.exchange.ExchangeRegistry; +import org.apache.qpid.server.management.JMXManagedObjectRegistry; +import org.apache.qpid.server.management.ManagedObjectRegistry; +import org.apache.qpid.server.management.ManagementConfiguration; +import org.apache.qpid.server.management.NoopManagedObjectRegistry; +import org.apache.qpid.server.queue.DefaultQueueRegistry; +import org.apache.qpid.server.queue.QueueRegistry; +import org.apache.qpid.server.security.auth.AuthenticationManager; +import org.apache.qpid.server.security.auth.SASLAuthenticationManager; +import org.apache.qpid.server.store.MessageStore; + +import java.io.File; + +public class ConfigurationFileApplicationRegistry extends ApplicationRegistry +{ + private QueueRegistry _queueRegistry; + + private ExchangeRegistry _exchangeRegistry; + + private ExchangeFactory _exchangeFactory; + + private ManagedObjectRegistry _managedObjectRegistry; + + private AuthenticationManager _authenticationManager; + + private MessageStore _messageStore; + + public ConfigurationFileApplicationRegistry(File configurationURL) throws ConfigurationException + { + super(config(configurationURL)); + } + + // Our configuration class needs to make the interpolate method + // public so it can be called below from the config method. + private static class MyConfiguration extends CompositeConfiguration { + public String interpolate(String obj) { + return super.interpolate(obj); + } + } + + private static final Configuration config(File url) throws ConfigurationException { + // We have to override the interpolate methods so that + // interpolation takes place accross the entirety of the + // composite configuration. Without doing this each + // configuration object only interpolates variables defined + // inside itself. + final MyConfiguration conf = new MyConfiguration(); + conf.addConfiguration(new SystemConfiguration() { + protected String interpolate(String o) { + return conf.interpolate(o); + } + }); + conf.addConfiguration(new XMLConfiguration(url) { + protected String interpolate(String o) { + return conf.interpolate(o); + } + }); + return conf; + } + + public void initialise() throws Exception + { + initialiseManagedObjectRegistry(); + _queueRegistry = new DefaultQueueRegistry(); + _exchangeFactory = new DefaultExchangeFactory(); + _exchangeRegistry = new DefaultExchangeRegistry(_exchangeFactory); + _authenticationManager = new SASLAuthenticationManager(); + initialiseMessageStore(); + } + + private void initialiseManagedObjectRegistry() + { + ManagementConfiguration config = getConfiguredObject(ManagementConfiguration.class); + if (config.enabled) + { + _managedObjectRegistry = new JMXManagedObjectRegistry(); + } + else + { + _managedObjectRegistry = new NoopManagedObjectRegistry(); + } + } + + private void initialiseMessageStore() throws Exception + { + String messageStoreClass = _configuration.getString("store.class"); + Class clazz = Class.forName(messageStoreClass); + Object o = clazz.newInstance(); + + if (!(o instanceof MessageStore)) + { + throw new Exception("Message store class must implement " + MessageStore.class + ". Class " + clazz + + " does not."); + } + _messageStore = (MessageStore) o; + _messageStore.configure(getQueueRegistry(), "store", _configuration); + } + + public QueueRegistry getQueueRegistry() + { + return _queueRegistry; + } + + public ExchangeRegistry getExchangeRegistry() + { + return _exchangeRegistry; + } + + public ExchangeFactory getExchangeFactory() + { + return _exchangeFactory; + } + + public ManagedObjectRegistry getManagedObjectRegistry() + { + return _managedObjectRegistry; + } + + public AuthenticationManager getAuthenticationManager() + { + return _authenticationManager; + } + + public MessageStore getMessageStore() + { + return _messageStore; + } +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java b/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java new file mode 100644 index 0000000000..cd664f9a4b --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.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.server.registry; + +import org.apache.qpid.server.exchange.ExchangeFactory; +import org.apache.qpid.server.exchange.ExchangeRegistry; +import org.apache.qpid.server.queue.QueueRegistry; +import org.apache.qpid.server.management.ManagedObjectRegistry; +import org.apache.qpid.server.security.auth.AuthenticationManager; +import org.apache.qpid.server.store.MessageStore; +import org.apache.commons.configuration.Configuration; + +public interface IApplicationRegistry +{ + /** + * Initialise the application registry. All initialisation must be done in this method so that any components + * that need access to the application registry itself for initialisation are able to use it. Attempting to + * initialise in the constructor will lead to failures since the registry reference will not have been set. + */ + void initialise() throws Exception; + + /** + * This gets access to a "configured object". A configured object has fields populated from a the configuration + * object (Commons Configuration) automatically, where it has the appropriate attributes defined on fields. + * Application registry implementations can choose the refresh strategy or caching approach. + * @param instanceType the type of object you want initialised. This must be unique - i.e. you can only + * have a single object of this type in the system. + * @return the configured object + */ + T getConfiguredObject(Class instanceType); + + /** + * Get the low level configuration. For use cases where the configured object approach is not required + * you can get the complete configuration information. + * @return a Commons Configuration instance + */ + Configuration getConfiguration(); + + QueueRegistry getQueueRegistry(); + + ExchangeRegistry getExchangeRegistry(); + + ExchangeFactory getExchangeFactory(); + + ManagedObjectRegistry getManagedObjectRegistry(); + + AuthenticationManager getAuthenticationManager(); + + MessageStore getMessageStore(); +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/auth/AuthenticationManager.java b/java/broker/src/main/java/org/apache/qpid/server/security/auth/AuthenticationManager.java new file mode 100644 index 0000000000..9f4addd7ee --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/security/auth/AuthenticationManager.java @@ -0,0 +1,33 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.security.auth; + +import javax.security.sasl.SaslException; +import javax.security.sasl.SaslServer; + +public interface AuthenticationManager +{ + String getMechanisms(); + + SaslServer createSaslServer(String mechanism, String localFQDN) throws SaslException; + + AuthenticationResult authenticate(SaslServer server, byte[] response); +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/auth/AuthenticationProviderInitialiser.java b/java/broker/src/main/java/org/apache/qpid/server/security/auth/AuthenticationProviderInitialiser.java new file mode 100644 index 0000000000..b26ba9b3dd --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/security/auth/AuthenticationProviderInitialiser.java @@ -0,0 +1,66 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.security.auth; + +import org.apache.commons.configuration.Configuration; + +import javax.security.auth.callback.CallbackHandler; +import javax.security.sasl.SaslServerFactory; +import java.util.Map; + +public interface AuthenticationProviderInitialiser +{ + /** + * @return the mechanism's name. This will be used in the list of mechanism's advertised to the + * client. + */ + String getMechanismName(); + + /** + * Initialise the authentication provider. + * @param baseConfigPath the path in the config file that points to any config options for this provider. Each + * provider can have its own set of configuration options + * @param configuration the Apache Commons Configuration instance used to configure this provider + * @param principalDatabases the set of principal databases that are available + */ + void initialise(String baseConfigPath, Configuration configuration, + Map principalDatabases) throws Exception; + + /** + * @return the callback handler that should be used to process authentication requests for this mechanism. This will + * be called after initialise and will be stored by the authentication manager. The callback handler must be + * fully threadsafe. + */ + CallbackHandler getCallbackHandler(); + + /** + * Get the properties that must be passed in to the Sasl.createSaslServer method. + * @return the properties, which may be null + */ + Map getProperties(); + + /** + * Get the class that is the server factory. This is used for the JCA registration. + * @return null if no JCA registration is required, otherwise return the class + * that will be used in JCA registration + */ + Class getServerFactoryClassForJCARegistration(); +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/auth/AuthenticationResult.java b/java/broker/src/main/java/org/apache/qpid/server/security/auth/AuthenticationResult.java new file mode 100644 index 0000000000..0e3aea4de0 --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/security/auth/AuthenticationResult.java @@ -0,0 +1,43 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.security.auth; + +public class AuthenticationResult +{ + public enum AuthenticationStatus + { + SUCCESS, CONTINUE, ERROR + } + + public AuthenticationStatus status; + public byte[] challenge; + + public AuthenticationResult(byte[] challenge, AuthenticationStatus status) + { + this.status = status; + this.challenge = challenge; + } + + public AuthenticationResult(AuthenticationStatus status) + { + this.status = status; + } +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/auth/CRAMMD5Initialiser.java b/java/broker/src/main/java/org/apache/qpid/server/security/auth/CRAMMD5Initialiser.java new file mode 100644 index 0000000000..4e428bbf23 --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/security/auth/CRAMMD5Initialiser.java @@ -0,0 +1,38 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.security.auth; + +import javax.security.sasl.SaslServerFactory; + +public class CRAMMD5Initialiser extends UsernamePasswordInitialiser +{ + public String getMechanismName() + { + return "CRAM-MD5"; + } + + public Class getServerFactoryClassForJCARegistration() + { + // since the CRAM-MD5 provider is registered as part of the JDK, we do not + // return the factory class here since we do not need to register it ourselves. + return null; + } +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/auth/JCAProvider.java b/java/broker/src/main/java/org/apache/qpid/server/security/auth/JCAProvider.java new file mode 100644 index 0000000000..f69e5dc708 --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/security/auth/JCAProvider.java @@ -0,0 +1,46 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.security.auth; + +import javax.security.sasl.SaslServerFactory; +import java.security.Provider; +import java.security.Security; +import java.util.Map; + +public final class JCAProvider extends Provider +{ + public JCAProvider(Map> providerMap) + { + super("AMQSASLProvider", 1.0, "A JCA provider that registers all " + + "AMQ SASL providers that want to be registered"); + register(providerMap); + Security.addProvider(this); + } + + private void register(Map> providerMap) + { + for (Map.Entry> me : + providerMap.entrySet()) + { + put("SaslServerFactory." + me.getKey(), me.getValue().getName()); + } + } +} \ No newline at end of file diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/auth/NullAuthenticationManager.java b/java/broker/src/main/java/org/apache/qpid/server/security/auth/NullAuthenticationManager.java new file mode 100644 index 0000000000..14cce86715 --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/security/auth/NullAuthenticationManager.java @@ -0,0 +1,85 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.security.auth; + +import org.apache.qpid.server.security.auth.AuthenticationManager; +import org.apache.qpid.server.security.auth.AuthenticationResult; + +import javax.security.sasl.SaslException; +import javax.security.sasl.SaslServer; + +public class NullAuthenticationManager implements AuthenticationManager +{ + public String getMechanisms() + { + return "PLAIN"; + } + + public SaslServer createSaslServer(String mechanism, String localFQDN) throws SaslException + { + return new SaslServer() + { + public String getMechanismName() + { + return "PLAIN"; + } + + public byte[] evaluateResponse(byte[] response) throws SaslException + { + return new byte[0]; + } + + public boolean isComplete() + { + return true; + } + + public String getAuthorizationID() + { + return "guest"; + } + + public byte[] unwrap(byte[] incoming, int offset, int len) throws SaslException + { + return new byte[0]; + } + + public byte[] wrap(byte[] outgoing, int offset, int len) throws SaslException + { + return new byte[0]; + } + + public Object getNegotiatedProperty(String propName) + { + return null; + } + + public void dispose() throws SaslException + { + } + }; + } + + public AuthenticationResult authenticate(SaslServer server, byte[] response) + { + return new AuthenticationResult(AuthenticationResult.AuthenticationStatus.SUCCESS); + } +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/auth/PasswordFilePrincipalDatabase.java b/java/broker/src/main/java/org/apache/qpid/server/security/auth/PasswordFilePrincipalDatabase.java new file mode 100644 index 0000000000..fb2ac612b6 --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/security/auth/PasswordFilePrincipalDatabase.java @@ -0,0 +1,133 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.security.auth; + +import org.apache.log4j.Logger; + +import javax.security.auth.callback.PasswordCallback; +import javax.security.auth.login.AccountNotFoundException; +import java.security.Principal; +import java.io.*; +import java.util.regex.Pattern; + +/** + * Represents a user database where the account information is stored in a simple flat file. + * + * The file is expected to be in the form: + * username:password + * username1:password1 + * ... + * usernamen:passwordn + * + * where a carriage return separates each username/password pair. Passwords are assumed to be in + * plain text. + * + */ +public class PasswordFilePrincipalDatabase implements PrincipalDatabase +{ + private static final Logger _logger = Logger.getLogger(PasswordFilePrincipalDatabase.class); + + private File _passwordFile; + + private Pattern _regexp = Pattern.compile(":"); + + public PasswordFilePrincipalDatabase() + { + } + + public void setPasswordFile(String passwordFile) throws FileNotFoundException + { + File f = new File(passwordFile); + _logger.info("PasswordFilePrincipalDatabase using file " + f.getAbsolutePath()); + _passwordFile = f; + if (!f.exists()) + { + throw new FileNotFoundException("Cannot find password file " + f); + } + if (!f.canRead()) + { + throw new FileNotFoundException("Cannot read password file " + f + + ". Check permissions."); + } + } + + public void setPassword(Principal principal, PasswordCallback callback) throws IOException, + AccountNotFoundException + { + if (_passwordFile == null) + { + throw new AccountNotFoundException("Unable to locate principal since no password file was specified during initialisation"); + } + if (principal == null) + { + throw new IllegalArgumentException("principal must not be null"); + } + char[] pwd = lookupPassword(principal.getName()); + if (pwd != null) + { + callback.setPassword(pwd); + } + else + { + throw new AccountNotFoundException("No account found for principal " + principal); + } + } + + /** + * Looks up the password for a specified user in the password file. + * Note this code is not secure since it creates strings of passwords. It should be modified + * to create only char arrays which get nulled out. + * @param name + * @return + * @throws IOException + */ + private char[] lookupPassword(String name) throws IOException + { + BufferedReader reader = null; + try + { + reader = new BufferedReader(new FileReader(_passwordFile)); + String line; + + while ((line = reader.readLine()) != null) + { + String[] result = _regexp.split(line); + if (result == null || result.length < 2) + { + continue; + } + + if (name.equals(result[0])) + { + return result[1].toCharArray(); + } + } + return null; + } + finally + { + if (reader != null) + { + reader.close(); + } + } + } +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/auth/PrincipalDatabase.java b/java/broker/src/main/java/org/apache/qpid/server/security/auth/PrincipalDatabase.java new file mode 100644 index 0000000000..d7fe21735f --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/security/auth/PrincipalDatabase.java @@ -0,0 +1,45 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.security.auth; + +import javax.security.auth.callback.PasswordCallback; +import javax.security.auth.login.AccountNotFoundException; +import java.security.Principal; +import java.io.IOException; + +/** + * Represents a "user database" which is really a way of storing principals (i.e. usernames) and + * passwords. + */ +public interface PrincipalDatabase +{ + /** + * Set the password for a given principal in the specified callback. This is used for certain + * SASL providers. The user database implementation should look up the password in any way it + * chooses and set it in the callback by calling its setPassword method. + * @param principal the principal + * @param callback the password callback that wants to receive the password + * @throws AccountNotFoundException if the account for specified principal could not be found + * @throws IOException if there was an error looking up the principal + */ + void setPassword(Principal principal, PasswordCallback callback) + throws IOException, AccountNotFoundException; +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/auth/SASLAuthenticationManager.java b/java/broker/src/main/java/org/apache/qpid/server/security/auth/SASLAuthenticationManager.java new file mode 100644 index 0000000000..21eb80c69d --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/security/auth/SASLAuthenticationManager.java @@ -0,0 +1,227 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.security.auth; + +import org.apache.commons.configuration.Configuration; +import org.apache.log4j.Logger; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.configuration.PropertyUtils; + +import javax.security.auth.callback.CallbackHandler; +import javax.security.sasl.Sasl; +import javax.security.sasl.SaslException; +import javax.security.sasl.SaslServer; +import javax.security.sasl.SaslServerFactory; +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; +import java.security.Security; + +public class SASLAuthenticationManager implements AuthenticationManager +{ + private static final Logger _log = Logger.getLogger(SASLAuthenticationManager.class); + + /** + * The list of mechanisms, in the order in which they are configured (i.e. preferred order) + */ + private String _mechanisms; + + /** + * Maps from the mechanism to the callback handler to use for handling those requests + */ + private Map _callbackHandlerMap = new HashMap(); + + /** + * Maps from the mechanism to the properties used to initialise the server. See the method + * Sasl.createSaslServer for details of the use of these properties. This map is populated during initialisation + * of each provider. + */ + private Map> _serverCreationProperties = new HashMap>(); + + public SASLAuthenticationManager() throws Exception + { + _log.info("Initialising SASL authentication manager"); + Map databases = initialisePrincipalDatabases(); + initialiseAuthenticationMechanisms(databases); + } + + private Map initialisePrincipalDatabases() throws Exception + { + Configuration config = ApplicationRegistry.getInstance().getConfiguration(); + List databaseNames = config.getList("security.principal-databases.principal-database.name"); + List databaseClasses = config.getList("security.principal-databases.principal-database.class"); + Map databases = new HashMap(); + for (int i = 0; i < databaseNames.size(); i++) + { + Object o; + try + { + o = Class.forName(databaseClasses.get(i)).newInstance(); + } + catch (Exception e) + { + throw new Exception("Error initialising principal database: " + e, e); + } + + if (!(o instanceof PrincipalDatabase)) + { + throw new Exception("Principal databases must implement the PrincipalDatabase interface"); + } + + initialisePrincipalDatabase((PrincipalDatabase) o, config, i); + + String name = databaseNames.get(i); + if (name == null || name.length() == 0) + { + throw new Exception("Principal database names must have length greater than or equal to one character"); + } + PrincipalDatabase pd = databases.get(name); + if (pd != null) + { + throw new Exception("Duplicate principal database name provided"); + } + _log.info("Initialised principal database " + name + " successfully"); + databases.put(name, (PrincipalDatabase) o); + } + return databases; + } + + private void initialisePrincipalDatabase(PrincipalDatabase principalDatabase, Configuration config, int index) + throws Exception + { + String baseName = "security.principal-databases.principal-database(" + index + ").attributes.attribute."; + List argumentNames = config.getList(baseName + "name"); + List argumentValues = config.getList(baseName + "value"); + for (int i = 0; i < argumentNames.size(); i++) + { + String argName = argumentNames.get(i); + if (argName == null || argName.length() == 0) + { + throw new Exception("Argument names must have length >= 1 character"); + } + if (Character.isLowerCase(argName.charAt(0))) + { + argName = Character.toUpperCase(argName.charAt(0)) + argName.substring(1); + } + String methodName = "set" + argName; + Method method = principalDatabase.getClass().getMethod(methodName, String.class); + if (method == null) + { + throw new Exception("No method " + methodName + " found in class " + principalDatabase.getClass() + + " hence unable to configure principal database. The method must be public and " + + "have a single String argument with a void return type"); + } + method.invoke(principalDatabase, PropertyUtils.replaceProperties(argumentValues.get(i))); + } + } + + private void initialiseAuthenticationMechanisms(Map databases) throws Exception + { + Configuration config = ApplicationRegistry.getInstance().getConfiguration(); + List mechanisms = config.getList("security.sasl.mechanisms.mechanism.initialiser.class"); + + // Maps from the mechanism to the properties used to initialise the server. See the method + // Sasl.createSaslServer for details of the use of these properties. This map is populated during initialisation + // of each provider. + Map> providerMap = new TreeMap>(); + + for (int i = 0; i < mechanisms.size(); i++) + { + String baseName = "security.sasl.mechanisms.mechanism(" + i + ").initialiser"; + String clazz = config.getString(baseName + ".class"); + initialiseAuthenticationMechanism(baseName, clazz, databases, config, providerMap); + } + if (providerMap.size() > 0) + { + Security.addProvider(new JCAProvider(providerMap)); + } + } + + private void initialiseAuthenticationMechanism(String baseName, String clazz, + Map databases, + Configuration configuration, + Map> providerMap) + throws Exception + { + Class initialiserClazz = Class.forName(clazz); + Object o = initialiserClazz.newInstance(); + if (!(o instanceof AuthenticationProviderInitialiser)) + { + throw new Exception("The class " + clazz + " must be an instance of " + + AuthenticationProviderInitialiser.class); + } + AuthenticationProviderInitialiser initialiser = (AuthenticationProviderInitialiser) o; + initialiser.initialise(baseName, configuration, databases); + String mechanism = initialiser.getMechanismName(); + if (_mechanisms == null) + { + _mechanisms = mechanism; + } + else + { + // simple append should be fine since the number of mechanisms is small and this is a one time initialisation + _mechanisms = _mechanisms + " " + mechanism; + } + _callbackHandlerMap.put(mechanism, initialiser.getCallbackHandler()); + _serverCreationProperties.put(mechanism, initialiser.getProperties()); + Class factory = initialiser.getServerFactoryClassForJCARegistration(); + if (factory != null) + { + providerMap.put(mechanism, factory); + } + _log.info("Initialised " + mechanism + " SASL provider successfully"); + } + + public String getMechanisms() + { + return _mechanisms; + } + + public SaslServer createSaslServer(String mechanism, String localFQDN) throws SaslException + { + return Sasl.createSaslServer(mechanism, "AMQP", localFQDN, _serverCreationProperties.get(mechanism), + _callbackHandlerMap.get(mechanism)); + } + + public AuthenticationResult authenticate(SaslServer server, byte[] response) + { + try + { + // Process response from the client + byte[] challenge = server.evaluateResponse(response != null ? response : new byte[0]); + + if (server.isComplete()) + { + return new AuthenticationResult(challenge, AuthenticationResult.AuthenticationStatus.SUCCESS); + } + else + { + return new AuthenticationResult(challenge, AuthenticationResult.AuthenticationStatus.CONTINUE); + } + } + catch (SaslException e) + { + return new AuthenticationResult(AuthenticationResult.AuthenticationStatus.ERROR); + } + } +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/auth/UsernamePasswordInitialiser.java b/java/broker/src/main/java/org/apache/qpid/server/security/auth/UsernamePasswordInitialiser.java new file mode 100644 index 0000000000..fccb881eaa --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/security/auth/UsernamePasswordInitialiser.java @@ -0,0 +1,102 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.security.auth; + +import org.apache.commons.configuration.Configuration; + +import javax.security.auth.callback.*; +import javax.security.auth.login.AccountNotFoundException; +import javax.security.sasl.AuthorizeCallback; +import java.util.Map; +import java.io.IOException; +import java.security.Principal; + +public abstract class UsernamePasswordInitialiser implements AuthenticationProviderInitialiser +{ + private ServerCallbackHandler _callbackHandler; + + private class ServerCallbackHandler implements CallbackHandler + { + private final PrincipalDatabase _principalDatabase; + + protected ServerCallbackHandler(PrincipalDatabase database) + { + _principalDatabase = database; + } + + public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException + { + Principal username = null; + for (Callback callback : callbacks) + { + if (callback instanceof NameCallback) + { + username = new UsernamePrincipal(((NameCallback)callback).getDefaultName()); + } + else if (callback instanceof PasswordCallback) + { + try + { + _principalDatabase.setPassword(username, (PasswordCallback) callback); + } + catch (AccountNotFoundException e) + { + // very annoyingly the callback handler does not throw anything more appropriate than + // IOException + throw new IOException("Error looking up user " + e); + } + } + else if (callback instanceof AuthorizeCallback) + { + ((AuthorizeCallback)callback).setAuthorized(true); + } + else + { + throw new UnsupportedCallbackException(callback); + } + } + } + } + + public void initialise(String baseConfigPath, Configuration configuration, + Map principalDatabases) throws Exception + { + String principalDatabaseName = configuration.getString(baseConfigPath + ".principal-database"); + PrincipalDatabase db = principalDatabases.get(principalDatabaseName); + if (db == null) + { + throw new Exception("Principal database " + principalDatabaseName + " not found. Ensure the name matches " + + "an entry in the configuration file"); + } + _callbackHandler = new ServerCallbackHandler(db); + } + + public CallbackHandler getCallbackHandler() + { + return _callbackHandler; + } + + public Map getProperties() + { + // there are no properties required for the CRAM-MD5 implementation + return null; + } +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/auth/UsernamePrincipal.java b/java/broker/src/main/java/org/apache/qpid/server/security/auth/UsernamePrincipal.java new file mode 100644 index 0000000000..e068ba6fe4 --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/security/auth/UsernamePrincipal.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.server.security.auth; + +import java.security.Principal; + +/** + * A principal that is just a wrapper for a simple username. + * + */ +public class UsernamePrincipal implements Principal +{ + private String _name; + + public UsernamePrincipal(String name) + { + _name = name; + } + + public String getName() + { + return _name; + } +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/auth/amqplain/AmqPlainInitialiser.java b/java/broker/src/main/java/org/apache/qpid/server/security/auth/amqplain/AmqPlainInitialiser.java new file mode 100644 index 0000000000..1d5932ca31 --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/security/auth/amqplain/AmqPlainInitialiser.java @@ -0,0 +1,38 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.security.auth.amqplain; + +import org.apache.qpid.server.security.auth.UsernamePasswordInitialiser; + +import javax.security.sasl.SaslServerFactory; + +public class AmqPlainInitialiser extends UsernamePasswordInitialiser +{ + public String getMechanismName() + { + return "AMQPLAIN"; + } + + public Class getServerFactoryClassForJCARegistration() + { + return AmqPlainSaslServerFactory.class; + } +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/auth/amqplain/AmqPlainSaslServer.java b/java/broker/src/main/java/org/apache/qpid/server/security/auth/amqplain/AmqPlainSaslServer.java new file mode 100644 index 0000000000..3ad74ce180 --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/security/auth/amqplain/AmqPlainSaslServer.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.server.security.auth.amqplain; + +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.framing.AMQFrameDecodingException; +import org.apache.mina.common.ByteBuffer; + +import javax.security.sasl.SaslServer; +import javax.security.sasl.SaslException; +import javax.security.sasl.AuthorizeCallback; +import javax.security.auth.callback.*; +import java.io.IOException; + +public class AmqPlainSaslServer implements SaslServer +{ + public static final String MECHANISM = "AMQPLAIN"; + + private CallbackHandler _cbh; + + private String _authorizationId; + + private boolean _complete = false; + + public AmqPlainSaslServer(CallbackHandler cbh) + { + _cbh = cbh; + } + + public String getMechanismName() + { + return MECHANISM; + } + + public byte[] evaluateResponse(byte[] response) throws SaslException + { + try + { + final FieldTable ft = new FieldTable(ByteBuffer.wrap(response), response.length); + String username = (String) ft.get("LOGIN"); + // we do not care about the prompt but it throws if null + NameCallback nameCb = new NameCallback("prompt", username); + // we do not care about the prompt but it throws if null + PasswordCallback passwordCb = new PasswordCallback("prompt", false); + // TODO: should not get pwd as a String but as a char array... + String pwd = (String) ft.get("PASSWORD"); + passwordCb.setPassword(pwd.toCharArray()); + AuthorizeCallback authzCb = new AuthorizeCallback(username, username); + Callback[] callbacks = new Callback[]{nameCb, passwordCb, authzCb}; + _cbh.handle(callbacks); + _complete = true; + if (authzCb.isAuthorized()) + { + _authorizationId = authzCb.getAuthenticationID(); + return null; + } + else + { + throw new SaslException("Authentication failed"); + } + } + catch (AMQFrameDecodingException e) + { + throw new SaslException("Unable to decode response: " + e, e); + } + catch (IOException e) + { + throw new SaslException("Error processing data: " + e, e); + } + catch (UnsupportedCallbackException e) + { + throw new SaslException("Unable to obtain data from callback handler: " + e, e); + } + } + + public boolean isComplete() + { + return _complete; + } + + public String getAuthorizationID() + { + return _authorizationId; + } + + public byte[] unwrap(byte[] incoming, int offset, int len) throws SaslException + { + throw new SaslException("Unsupported operation"); + } + + public byte[] wrap(byte[] outgoing, int offset, int len) throws SaslException + { + throw new SaslException("Unsupported operation"); + } + + public Object getNegotiatedProperty(String propName) + { + return null; + } + + public void dispose() throws SaslException + { + _cbh = null; + } +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/auth/amqplain/AmqPlainSaslServerFactory.java b/java/broker/src/main/java/org/apache/qpid/server/security/auth/amqplain/AmqPlainSaslServerFactory.java new file mode 100644 index 0000000000..befd724b33 --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/security/auth/amqplain/AmqPlainSaslServerFactory.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.server.security.auth.amqplain; + +import javax.security.sasl.SaslServerFactory; +import javax.security.sasl.SaslServer; +import javax.security.sasl.SaslException; +import javax.security.sasl.Sasl; +import javax.security.auth.callback.CallbackHandler; +import java.util.Map; + +public class AmqPlainSaslServerFactory implements SaslServerFactory +{ + public SaslServer createSaslServer(String mechanism, String protocol, String serverName, Map props, + CallbackHandler cbh) throws SaslException + { + if (AmqPlainSaslServer.MECHANISM.equals(mechanism)) + { + return new AmqPlainSaslServer(cbh); + } + else + { + 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[]{AmqPlainSaslServer.MECHANISM}; + } + } +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/auth/plain/PlainInitialiser.java b/java/broker/src/main/java/org/apache/qpid/server/security/auth/plain/PlainInitialiser.java new file mode 100644 index 0000000000..b92e0b9209 --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/security/auth/plain/PlainInitialiser.java @@ -0,0 +1,38 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.security.auth.plain; + +import org.apache.qpid.server.security.auth.UsernamePasswordInitialiser; + +import javax.security.sasl.SaslServerFactory; + +public class PlainInitialiser extends UsernamePasswordInitialiser +{ + public String getMechanismName() + { + return "PLAIN"; + } + + public Class getServerFactoryClassForJCARegistration() + { + return PlainSaslServerFactory.class; + } +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/auth/plain/PlainSaslServer.java b/java/broker/src/main/java/org/apache/qpid/server/security/auth/plain/PlainSaslServer.java new file mode 100644 index 0000000000..fdf655c2d9 --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/security/auth/plain/PlainSaslServer.java @@ -0,0 +1,144 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.security.auth.plain; + +import javax.security.auth.callback.*; +import javax.security.sasl.AuthorizeCallback; +import javax.security.sasl.SaslException; +import javax.security.sasl.SaslServer; +import java.io.IOException; + +public class PlainSaslServer implements SaslServer +{ + public static final String MECHANISM = "PLAIN"; + + private CallbackHandler _cbh; + + private String _authorizationId; + + private boolean _complete = false; + + public PlainSaslServer(CallbackHandler cbh) + { + _cbh = cbh; + } + + public String getMechanismName() + { + return MECHANISM; + } + + public byte[] evaluateResponse(byte[] response) throws SaslException + { + try + { + int authzidNullPosition = findNullPosition(response, 0); + if (authzidNullPosition < 0) + { + throw new SaslException("Invalid PLAIN encoding, authzid null terminator not found"); + } + int authcidNullPosition = findNullPosition(response, authzidNullPosition + 1); + if (authcidNullPosition < 0) + { + throw new SaslException("Invalid PLAIN encoding, authcid null terminator not found"); + } + + // we do not currently support authcid in any meaningful way + String authcid = new String(response, 0, authzidNullPosition, "utf8"); + String authzid = new String(response, authzidNullPosition + 1, authcidNullPosition - 1, "utf8"); + + // we do not care about the prompt but it throws if null + NameCallback nameCb = new NameCallback("prompt", authzid); + // we do not care about the prompt but it throws if null + PasswordCallback passwordCb = new PasswordCallback("prompt", false); + // TODO: should not get pwd as a String but as a char array... + int passwordLen = response.length - authcidNullPosition - 1; + String pwd = new String(response, authcidNullPosition + 1, passwordLen, "utf8"); + passwordCb.setPassword(pwd.toCharArray()); + AuthorizeCallback authzCb = new AuthorizeCallback(authzid, authzid); + Callback[] callbacks = new Callback[]{nameCb, passwordCb, authzCb}; + _cbh.handle(callbacks); + _complete = true; + if (authzCb.isAuthorized()) + { + _authorizationId = authzCb.getAuthenticationID(); + return null; + } + else + { + throw new SaslException("Authentication failed"); + } + } + catch (IOException e) + { + throw new SaslException("Error processing data: " + e, e); + } + catch (UnsupportedCallbackException e) + { + throw new SaslException("Unable to obtain data from callback handler: " + e, e); + } + } + + private int findNullPosition(byte[] response, int startPosition) + { + int position = startPosition; + while (position < response.length) + { + if (response[position] == (byte) 0) + { + return position; + } + position++; + } + return -1; + } + + public boolean isComplete() + { + return _complete; + } + + public String getAuthorizationID() + { + return _authorizationId; + } + + public byte[] unwrap(byte[] incoming, int offset, int len) throws SaslException + { + throw new SaslException("Unsupported operation"); + } + + public byte[] wrap(byte[] outgoing, int offset, int len) throws SaslException + { + throw new SaslException("Unsupported operation"); + } + + public Object getNegotiatedProperty(String propName) + { + return null; + } + + public void dispose() throws SaslException + { + _cbh = null; + } + +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/auth/plain/PlainSaslServerFactory.java b/java/broker/src/main/java/org/apache/qpid/server/security/auth/plain/PlainSaslServerFactory.java new file mode 100644 index 0000000000..444f7d9b58 --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/security/auth/plain/PlainSaslServerFactory.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.server.security.auth.plain; + +import javax.security.auth.callback.CallbackHandler; +import javax.security.sasl.Sasl; +import javax.security.sasl.SaslException; +import javax.security.sasl.SaslServer; +import javax.security.sasl.SaslServerFactory; +import java.util.Map; + +public class PlainSaslServerFactory implements SaslServerFactory +{ + public SaslServer createSaslServer(String mechanism, String protocol, String serverName, Map props, + CallbackHandler cbh) throws SaslException + { + if (PlainSaslServer.MECHANISM.equals(mechanism)) + { + return new PlainSaslServer(cbh); + } + else + { + 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[]{PlainSaslServer.MECHANISM}; + } + } +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/state/AMQState.java b/java/broker/src/main/java/org/apache/qpid/server/state/AMQState.java new file mode 100644 index 0000000000..f427cc7206 --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/state/AMQState.java @@ -0,0 +1,36 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.state; + +/** + * States used in the AMQ protocol. Used by the finite state machine to determine + * valid responses. + */ +public enum AMQState +{ + CONNECTION_NOT_STARTED, + CONNECTION_NOT_AUTH, + CONNECTION_NOT_TUNED, + CONNECTION_NOT_OPENED, + CONNECTION_OPEN, + CONNECTION_CLOSING, + CONNECTION_CLOSED +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/state/AMQStateManager.java b/java/broker/src/main/java/org/apache/qpid/server/state/AMQStateManager.java new file mode 100644 index 0000000000..5e88ff7f2d --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/state/AMQStateManager.java @@ -0,0 +1,222 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.state; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.*; +import org.apache.qpid.server.exchange.ExchangeRegistry; +import org.apache.qpid.server.handler.*; +import org.apache.qpid.server.protocol.AMQMethodEvent; +import org.apache.qpid.server.protocol.AMQMethodListener; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.queue.QueueRegistry; +import org.apache.log4j.Logger; + +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.CopyOnWriteArraySet; + +/** + * The state manager is responsible for managing the state of the protocol session. + *

    + * For each AMQProtocolHandler there is a separate state manager. + * + */ +public class AMQStateManager implements AMQMethodListener +{ + private static final Logger _logger = Logger.getLogger(AMQStateManager.class); + + /** + * 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. + */ + private final Map, StateAwareMethodListener>> _state2HandlersMap = + new HashMap, StateAwareMethodListener>>(); + + private CopyOnWriteArraySet _stateListeners = new CopyOnWriteArraySet(); + + public AMQStateManager() + { + this(AMQState.CONNECTION_NOT_STARTED, true); + } + + protected AMQStateManager(AMQState initial, boolean register) + { + _currentState = initial; + if (register) + { + registerListeners(); + } + } + + protected void registerListeners() + { + Map, StateAwareMethodListener> frame2handlerMap = + new HashMap, StateAwareMethodListener>(); + + // 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, StateAwareMethodListener>(); + frame2handlerMap.put(ConnectionStartOkBody.class, ConnectionStartOkMethodHandler.getInstance()); + _state2HandlersMap.put(AMQState.CONNECTION_NOT_STARTED, frame2handlerMap); + + frame2handlerMap = new HashMap, StateAwareMethodListener>(); + frame2handlerMap.put(ConnectionSecureOkBody.class, ConnectionSecureOkMethodHandler.getInstance()); + _state2HandlersMap.put(AMQState.CONNECTION_NOT_AUTH, frame2handlerMap); + + frame2handlerMap = new HashMap, StateAwareMethodListener>(); + frame2handlerMap.put(ConnectionTuneOkBody.class, ConnectionTuneOkMethodHandler.getInstance()); + _state2HandlersMap.put(AMQState.CONNECTION_NOT_TUNED, frame2handlerMap); + + frame2handlerMap = new HashMap, StateAwareMethodListener>(); + frame2handlerMap.put(ConnectionOpenBody.class, ConnectionOpenMethodHandler.getInstance()); + _state2HandlersMap.put(AMQState.CONNECTION_NOT_OPENED, frame2handlerMap); + + // + // ConnectionOpen handlers + // + frame2handlerMap = new HashMap, StateAwareMethodListener>(); + frame2handlerMap.put(ChannelOpenBody.class, ChannelOpenHandler.getInstance()); + frame2handlerMap.put(ChannelCloseBody.class, ChannelCloseHandler.getInstance()); + frame2handlerMap.put(ChannelCloseOkBody.class, ChannelCloseOkHandler.getInstance()); + frame2handlerMap.put(ConnectionCloseBody.class, ConnectionCloseMethodHandler.getInstance()); + frame2handlerMap.put(ExchangeDeclareBody.class, ExchangeDeclareHandler.getInstance()); + frame2handlerMap.put(ExchangeDeleteBody.class, ExchangeDeleteHandler.getInstance()); + frame2handlerMap.put(BasicAckBody.class, BasicAckMethodHandler.getInstance()); + frame2handlerMap.put(BasicRecoverBody.class, BasicRecoverMethodHandler.getInstance()); + frame2handlerMap.put(BasicConsumeBody.class, BasicConsumeMethodHandler.getInstance()); + frame2handlerMap.put(BasicCancelBody.class, BasicCancelMethodHandler.getInstance()); + frame2handlerMap.put(BasicPublishBody.class, BasicPublishMethodHandler.getInstance()); + frame2handlerMap.put(BasicQosBody.class, BasicQosHandler.getInstance()); + frame2handlerMap.put(QueueBindBody.class, QueueBindHandler.getInstance()); + frame2handlerMap.put(QueueDeclareBody.class, QueueDeclareHandler.getInstance()); + frame2handlerMap.put(QueueDeleteBody.class, QueueDeleteHandler.getInstance()); + frame2handlerMap.put(ChannelFlowBody.class, ChannelFlowHandler.getInstance()); + frame2handlerMap.put(TxSelectBody.class, TxSelectHandler.getInstance()); + frame2handlerMap.put(TxCommitBody.class, TxCommitHandler.getInstance()); + frame2handlerMap.put(TxRollbackBody.class, TxRollbackHandler.getInstance()); + + _state2HandlersMap.put(AMQState.CONNECTION_OPEN, frame2handlerMap); + + frame2handlerMap = new HashMap, StateAwareMethodListener>(); + frame2handlerMap.put(ConnectionCloseOkBody.class, ConnectionCloseOkMethodHandler.getInstance()); + _state2HandlersMap.put(AMQState.CONNECTION_CLOSING, frame2handlerMap); + + } + + public AMQState getCurrentState() + { + return _currentState; + } + + public void changeState(AMQState newState) throws AMQException + { + _logger.debug("State changing to " + newState + " from old state " + _currentState); + final AMQState oldState = _currentState; + _currentState = newState; + + for (StateListener l : _stateListeners) + { + l.stateChanged(oldState, newState); + } + } + + public void error(AMQException e) + { + _logger.error("State manager received error notification: " + e, e); + for (StateListener l : _stateListeners) + { + l.error(e); + } + } + + public boolean methodReceived(AMQMethodEvent evt, + AMQProtocolSession protocolSession, + QueueRegistry queueRegistry, + ExchangeRegistry exchangeRegistry) throws AMQException + { + StateAwareMethodListener handler = findStateTransitionHandler(_currentState, evt.getMethod()); + if (handler != null) + { + handler.methodReceived(this, queueRegistry, exchangeRegistry, protocolSession, evt); + return true; + } + return false; + } + + protected StateAwareMethodListener findStateTransitionHandler(AMQState currentState, + B frame) + throws IllegalStateTransitionException + { + if (_logger.isDebugEnabled()) + { + _logger.debug("Looking for state transition handler for frame " + frame.getClass()); + } + final Map, StateAwareMethodListener> + classToHandlerMap = _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(frame.getClass()); + 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 addStateListener(StateListener listener) + { + _logger.debug("Adding state listener"); + _stateListeners.add(listener); + } + + public void removeStateListener(StateListener listener) + { + _stateListeners.remove(listener); + } +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/state/IllegalStateTransitionException.java b/java/broker/src/main/java/org/apache/qpid/server/state/IllegalStateTransitionException.java new file mode 100644 index 0000000000..2d7cc27a85 --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/state/IllegalStateTransitionException.java @@ -0,0 +1,48 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.state; + +import org.apache.qpid.AMQException; + +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/java/broker/src/main/java/org/apache/qpid/server/state/StateAwareMethodListener.java b/java/broker/src/main/java/org/apache/qpid/server/state/StateAwareMethodListener.java new file mode 100644 index 0000000000..7d58f242e5 --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/state/StateAwareMethodListener.java @@ -0,0 +1,40 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.state; + +import org.apache.qpid.AMQException; +import org.apache.qpid.server.protocol.AMQMethodEvent; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.queue.QueueRegistry; +import org.apache.qpid.server.exchange.ExchangeRegistry; +import org.apache.qpid.framing.AMQMethodBody; + +/** + * A frame listener that is informed of the protocol state when invoked and has + * the opportunity to update state. + * + */ +public interface StateAwareMethodListener +{ + void methodReceived(AMQStateManager stateManager, QueueRegistry queueRegistry, + ExchangeRegistry exchangeRegistry, AMQProtocolSession protocolSession, + AMQMethodEvent evt) throws AMQException; +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/state/StateListener.java b/java/broker/src/main/java/org/apache/qpid/server/state/StateListener.java new file mode 100644 index 0000000000..00fc09867b --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/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.server.state; + +import org.apache.qpid.AMQException; + +public interface StateListener +{ + void stateChanged(AMQState oldState, AMQState newState) throws AMQException; + + void error(Throwable t); +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java b/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java new file mode 100644 index 0000000000..328aed81d9 --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.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.server.store; + +import org.apache.commons.configuration.Configuration; +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.queue.QueueRegistry; + +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.atomic.AtomicLong; + +/** + * A simple message store that stores the messages in a threadsafe structure in memory. + */ +public class MemoryMessageStore implements MessageStore +{ + private static final Logger _log = Logger.getLogger(MemoryMessageStore.class); + + private static final int DEFAULT_HASHTABLE_CAPACITY = 50000; + + private static final String HASHTABLE_CAPACITY_CONFIG = "hashtable-capacity"; + + protected ConcurrentMap _messageMap; + + private final AtomicLong _messageId = new AtomicLong(1); + + public void configure() + { + _log.info("Using capacity " + DEFAULT_HASHTABLE_CAPACITY + " for hash table"); + _messageMap = new ConcurrentHashMap(DEFAULT_HASHTABLE_CAPACITY); + } + + public void configure(String base, Configuration config) + { + int hashtableCapacity = config.getInt(base + "." + HASHTABLE_CAPACITY_CONFIG, DEFAULT_HASHTABLE_CAPACITY); + _log.info("Using capacity " + hashtableCapacity + " for hash table"); + _messageMap = new ConcurrentHashMap(hashtableCapacity); + } + + public void configure(QueueRegistry queueRegistry, String base, Configuration config) throws Exception + { + configure(base, config); + } + + public void close() throws Exception + { + if (_messageMap != null) + { + _messageMap.clear(); + _messageMap = null; + } + } + + public void put(AMQMessage msg) + { + _messageMap.put(msg.getMessageId(), msg); + } + + public void removeMessage(long messageId) + { + if (_log.isDebugEnabled()) + { + _log.debug("Removing message with id " + messageId); + } + _messageMap.remove(messageId); + } + + public void createQueue(AMQQueue queue) throws AMQException + { + //To change body of implemented methods use File | Settings | File Templates. + } + + public void removeQueue(String name) throws AMQException + { + //To change body of implemented methods use File | Settings | File Templates. + } + + public void enqueueMessage(String name, long messageId) throws AMQException + { + //To change body of implemented methods use File | Settings | File Templates. + } + + public void dequeueMessage(String name, long messageId) throws AMQException + { + //To change body of implemented methods use File | Settings | File Templates. + } + + public void beginTran() throws AMQException + { + //To change body of implemented methods use File | Settings | File Templates. + } + + public void commitTran() throws AMQException + { + //To change body of implemented methods use File | Settings | File Templates. + } + + public void abortTran() throws AMQException + { + //To change body of implemented methods use File | Settings | File Templates. + } + + public boolean inTran() + { + return false; + } + + public List createQueues() throws AMQException + { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + public long getNewMessageId() + { + return _messageId.getAndIncrement(); + } + + public AMQMessage getMessage(long messageId) + { + return _messageMap.get(messageId); + } +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/store/MessageStore.java b/java/broker/src/main/java/org/apache/qpid/server/store/MessageStore.java new file mode 100644 index 0000000000..8ee1d09862 --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/store/MessageStore.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.server.store; + +import org.apache.commons.configuration.Configuration; +import org.apache.qpid.AMQException; +import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.queue.QueueRegistry; + +import java.util.List; + +public interface MessageStore +{ + /** + * Called after instantiation in order to configure the message store. A particular implementation can define + * whatever parameters it wants. + * @param queueRegistry the registry of queues to be used by this store + * @param base the base element identifier from which all configuration items are relative. For example, if the base + * element is "store", the all elements used by concrete classes will be "store.foo" etc. + * @param config the apache commons configuration object + */ + void configure(QueueRegistry queueRegistry, String base, Configuration config) throws Exception; + + /** + * Called to close and cleanup any resources used by the message store. + * @throws Exception + */ + void close() throws Exception; + + void put(AMQMessage msg) throws AMQException; + + void removeMessage(long messageId) throws AMQException; + + void createQueue(AMQQueue queue) throws AMQException; + + void removeQueue(String name) throws AMQException; + + void enqueueMessage(String name, long messageId) throws AMQException; + + void dequeueMessage(String name, long messageId) throws AMQException; + + void beginTran() throws AMQException; + + void commitTran() throws AMQException; + + void abortTran() throws AMQException; + + boolean inTran(); + + /** + * Recreate all queues that were persisted, including re-enqueuing of existing messages + * @return + * @throws AMQException + */ + List createQueues() throws AMQException; + + /** + * Return a valid, currently unused message id. + * @return a message id + */ + long getNewMessageId(); +} + + diff --git a/java/broker/src/main/java/org/apache/qpid/server/transport/ConnectorConfiguration.java b/java/broker/src/main/java/org/apache/qpid/server/transport/ConnectorConfiguration.java new file mode 100644 index 0000000000..ca008a0bd5 --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/transport/ConnectorConfiguration.java @@ -0,0 +1,86 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.transport; + +import org.apache.qpid.configuration.Configured; +import org.apache.mina.common.IoAcceptor; +import org.apache.mina.filter.executor.ExecutorExecutor; +import org.apache.mina.util.NewThreadExecutor; + +public class ConnectorConfiguration +{ + public static final String DEFAULT_PORT = "5672"; + + public static final String SSL_PORT = "8672"; + + @Configured(path = "connector.processors", + defaultValue = "4") + public int processors; + + @Configured(path = "connector.port", + defaultValue = DEFAULT_PORT) + public int port; + + @Configured(path = "connector.bind", + defaultValue = "wildcard") + public String bindAddress; + + @Configured(path = "connector.sslport", + defaultValue = SSL_PORT) + public int sslPort; + + @Configured(path = "connector.socketReceiveBuffer", + defaultValue = "32767") + public int socketReceiveBufferSize; + + @Configured(path = "connector.socketWriteBuffer", + defaultValue = "32767") + public int socketWriteBuferSize; + + @Configured(path = "connector.tcpNoDelay", + defaultValue = "true") + public boolean tcpNoDelay; + + @Configured(path = "advanced.filterchain[@enableExecutorPool]", + defaultValue = "false") + public boolean enableExecutorPool; + + @Configured(path = "advanced.enablePooledAllocator", + defaultValue = "false") + public boolean enablePooledAllocator; + + @Configured(path = "advanced.enableDirectBuffers", + defaultValue = "false") + public boolean enableDirectBuffers; + + @Configured(path = "connector.ssl", + defaultValue = "false") + public boolean enableSSL; + + @Configured(path = "connector.nonssl", + defaultValue = "true") + public boolean enableNonSSL; + + public IoAcceptor createAcceptor() + { + return new org.apache.mina.transport.socket.nio.SocketAcceptor(processors, new NewThreadExecutor()); + } +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/transport/ThreadPoolFilter.java b/java/broker/src/main/java/org/apache/qpid/server/transport/ThreadPoolFilter.java new file mode 100644 index 0000000000..2ee75c001f --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/transport/ThreadPoolFilter.java @@ -0,0 +1,695 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.transport; + +import org.apache.mina.common.*; +import org.apache.mina.util.*; +import org.apache.mina.util.Queue; +import org.apache.mina.util.Stack; + +import java.util.*; + +/** + * A Thread-pooling filter. This filter forwards {@link IoHandler} events + * to its thread pool. + *

    + * This is an implementation of + * Leader/Followers + * thread pool by Douglas C. Schmidt et al. + */ +public class ThreadPoolFilter extends IoFilterAdapter +{ + /** + * Default maximum size of thread pool (2G). + */ + public static final int DEFAULT_MAXIMUM_POOL_SIZE = Integer.MAX_VALUE; + + /** + * Default keep-alive time of thread pool (1 min). + */ + public static final int DEFAULT_KEEP_ALIVE_TIME = 60 * 1000; + + /** + * A queue which contains {@link Integer}s which represents reusable + * thread IDs. {@link Worker} first checks this queue and then + * uses {@link #threadId} when no reusable thread ID is available. + */ + private static final Queue threadIdReuseQueue = new Queue(); + private static int threadId = 0; + + private static int acquireThreadId() + { + synchronized (threadIdReuseQueue) + { + Integer id = (Integer) threadIdReuseQueue.pop(); + if (id == null) + { + return ++ threadId; + } + else + { + return id.intValue(); + } + } + } + + private static void releaseThreadId(int id) + { + synchronized (threadIdReuseQueue) + { + threadIdReuseQueue.push(new Integer(id)); + } + } + + private final String threadNamePrefix; + private final Map buffers = new IdentityHashMap(); + private final BlockingQueue unfetchedSessionBuffers = new BlockingQueue(); + private final Set allSessionBuffers = new IdentityHashSet(); + + private Worker leader; + private final Stack followers = new Stack(); + private final Set allWorkers = new IdentityHashSet(); + + private int maximumPoolSize = DEFAULT_MAXIMUM_POOL_SIZE; + private int keepAliveTime = DEFAULT_KEEP_ALIVE_TIME; + + private boolean shuttingDown; + + private int poolSize; + private final Object poolSizeLock = new Object(); + + /** + * Creates a new instance of this filter with default thread pool settings. + */ + public ThreadPoolFilter() + { + this("IoThreadPool"); + } + + /** + * Creates a new instance of this filter with the specified thread name prefix + * and other default settings. + * + * @param threadNamePrefix the prefix of the thread names this pool will create. + */ + public ThreadPoolFilter(String threadNamePrefix) + { + if (threadNamePrefix == null) + { + throw new NullPointerException("threadNamePrefix"); + } + threadNamePrefix = threadNamePrefix.trim(); + if (threadNamePrefix.length() == 0) + { + throw new IllegalArgumentException("threadNamePrefix is empty."); + } + this.threadNamePrefix = threadNamePrefix; + } + + public String getThreadNamePrefix() + { + return threadNamePrefix; + } + + public int getPoolSize() + { + synchronized (poolSizeLock) + { + return poolSize; + } + } + + public int getMaximumPoolSize() + { + return maximumPoolSize; + } + + public int getKeepAliveTime() + { + return keepAliveTime; + } + + public void setMaximumPoolSize(int maximumPoolSize) + { + if (maximumPoolSize <= 0) + { + throw new IllegalArgumentException(); + } + this.maximumPoolSize = maximumPoolSize; + } + + public void setKeepAliveTime(int keepAliveTime) + { + this.keepAliveTime = keepAliveTime; + } + + public void init() + { + shuttingDown = false; + leader = new Worker(); + leader.start(); + leader.lead(); + } + + public void destroy() + { + shuttingDown = true; + int expectedPoolSize = 0; + while (getPoolSize() != expectedPoolSize) + { + List allWorkers; + synchronized (poolSizeLock) + { + allWorkers = new ArrayList(this.allWorkers); + } + + // You may not interrupt the current thread. + if (allWorkers.remove(Thread.currentThread())) + { + expectedPoolSize = 1; + } + + for (Iterator i = allWorkers.iterator(); i.hasNext();) + { + Worker worker = (Worker) i.next(); + while (worker.isAlive()) + { + worker.interrupt(); + try + { + // This timeout will help us from + // infinite lock-up and interrupt workers again. + worker.join(100); + } + catch (InterruptedException e) + { + } + } + } + } + + this.allSessionBuffers.clear(); + this.unfetchedSessionBuffers.clear(); + this.buffers.clear(); + this.followers.clear(); + this.leader = null; + } + + private void increasePoolSize(Worker worker) + { + synchronized (poolSizeLock) + { + poolSize++; + allWorkers.add(worker); + } + } + + private void decreasePoolSize(Worker worker) + { + synchronized (poolSizeLock) + { + poolSize--; + allWorkers.remove(worker); + } + } + + private void fireEvent(NextFilter nextFilter, IoSession session, + EventType type, Object data) + { + final BlockingQueue unfetchedSessionBuffers = this.unfetchedSessionBuffers; + final Set allSessionBuffers = this.allSessionBuffers; + final Event event = new Event(type, nextFilter, data); + + synchronized (unfetchedSessionBuffers) + { + final SessionBuffer buf = getSessionBuffer(session); + final Queue eventQueue = buf.eventQueue; + + synchronized (buf) + { + eventQueue.push(event); + } + + if (!allSessionBuffers.contains(buf)) + { + allSessionBuffers.add(buf); + unfetchedSessionBuffers.push(buf); + } + } + } + + /** + * Implement this method to fetch (or pop) a {@link SessionBuffer} from + * the given unfetchedSessionBuffers. The default implementation + * simply pops the buffer from it. You could prioritize the fetch order. + * + * @return A non-null {@link SessionBuffer} + */ + protected SessionBuffer fetchSessionBuffer(Queue unfetchedSessionBuffers) + { + return (SessionBuffer) unfetchedSessionBuffers.pop(); + } + + private SessionBuffer getSessionBuffer(IoSession session) + { + final Map buffers = this.buffers; + SessionBuffer buf = (SessionBuffer) buffers.get(session); + if (buf == null) + { + synchronized (buffers) + { + buf = (SessionBuffer) buffers.get(session); + if (buf == null) + { + buf = new SessionBuffer(session); + buffers.put(session, buf); + } + } + } + return buf; + } + + private void removeSessionBuffer(SessionBuffer buf) + { + final Map buffers = this.buffers; + final IoSession session = buf.session; + synchronized (buffers) + { + buffers.remove(session); + } + } + + protected static class SessionBuffer + { + private final IoSession session; + + private final Queue eventQueue = new Queue(); + + private SessionBuffer(IoSession session) + { + this.session = session; + } + + public IoSession getSession() + { + return session; + } + + public Queue getEventQueue() + { + return eventQueue; + } + } + + private class Worker extends Thread + { + private final int id; + private final Object promotionLock = new Object(); + private boolean dead; + + private Worker() + { + int id = acquireThreadId(); + this.id = id; + this.setName(threadNamePrefix + '-' + id); + increasePoolSize(this); + } + + public boolean lead() + { + final Object promotionLock = this.promotionLock; + synchronized (promotionLock) + { + if (dead) + { + return false; + } + + leader = this; + promotionLock.notify(); + } + + return true; + } + + public void run() + { + for (; ;) + { + if (!waitForPromotion()) + { + break; + } + + SessionBuffer buf = fetchBuffer(); + giveUpLead(); + if (buf == null) + { + break; + } + + processEvents(buf); + follow(); + releaseBuffer(buf); + } + + decreasePoolSize(this); + releaseThreadId(id); + } + + private SessionBuffer fetchBuffer() + { + BlockingQueue unfetchedSessionBuffers = ThreadPoolFilter.this.unfetchedSessionBuffers; + synchronized (unfetchedSessionBuffers) + { + while (!shuttingDown) + { + try + { + unfetchedSessionBuffers.waitForNewItem(); + } + catch (InterruptedException e) + { + continue; + } + + return ThreadPoolFilter.this.fetchSessionBuffer(unfetchedSessionBuffers); + } + } + + return null; + } + + private void processEvents(SessionBuffer buf) + { + final IoSession session = buf.session; + final Queue eventQueue = buf.eventQueue; + for (; ;) + { + Event event; + synchronized (buf) + { + event = (Event) eventQueue.pop(); + if (event == null) + { + break; + } + } + processEvent(event.getNextFilter(), session, + event.getType(), event.getData()); + } + } + + private void follow() + { + final Object promotionLock = this.promotionLock; + final Stack followers = ThreadPoolFilter.this.followers; + synchronized (promotionLock) + { + if (this != leader) + { + synchronized (followers) + { + followers.push(this); + } + } + } + } + + private void releaseBuffer(SessionBuffer buf) + { + final BlockingQueue unfetchedSessionBuffers = ThreadPoolFilter.this.unfetchedSessionBuffers; + final Set allSessionBuffers = ThreadPoolFilter.this.allSessionBuffers; + final Queue eventQueue = buf.eventQueue; + + synchronized (unfetchedSessionBuffers) + { + if (eventQueue.isEmpty()) + { + allSessionBuffers.remove(buf); + removeSessionBuffer(buf); + } + else + { + unfetchedSessionBuffers.push(buf); + } + } + } + + private boolean waitForPromotion() + { + final Object promotionLock = this.promotionLock; + + long startTime = System.currentTimeMillis(); + long currentTime = System.currentTimeMillis(); + + synchronized (promotionLock) + { + while (this != leader && !shuttingDown) + { + // Calculate remaining keep-alive time + int keepAliveTime = getKeepAliveTime(); + if (keepAliveTime > 0) + { + keepAliveTime -= (currentTime - startTime); + } + else + { + keepAliveTime = Integer.MAX_VALUE; + } + + // Break the loop if there's no remaining keep-alive time. + if (keepAliveTime <= 0) + { + break; + } + + // Wait for promotion + try + { + promotionLock.wait(keepAliveTime); + } + catch (InterruptedException e) + { + } + + // Update currentTime for the next iteration + currentTime = System.currentTimeMillis(); + } + + boolean timeToLead = this == leader && !shuttingDown; + + if (!timeToLead) + { + // time to die + synchronized (followers) + { + followers.remove(this); + } + + // Mark as dead explicitly when we've got promotionLock. + dead = true; + } + + return timeToLead; + } + } + + private void giveUpLead() + { + final Stack followers = ThreadPoolFilter.this.followers; + Worker worker; + do + { + synchronized (followers) + { + worker = (Worker) followers.pop(); + } + + if (worker == null) + { + // Increase the number of threads if we + // are not shutting down and we can increase the number. + if (!shuttingDown + && getPoolSize() < getMaximumPoolSize()) + { + worker = new Worker(); + worker.lead(); + worker.start(); + } + + // This loop should end because: + // 1) lead() is called already, + // 2) or it is shutting down and there's no more threads left. + break; + } + } + while (!worker.lead()); + } + } + + protected static class EventType + { + public static final EventType OPENED = new EventType("OPENED"); + + public static final EventType CLOSED = new EventType("CLOSED"); + + public static final EventType READ = new EventType("READ"); + + public static final EventType WRITTEN = new EventType("WRITTEN"); + + public static final EventType RECEIVED = new EventType("RECEIVED"); + + public static final EventType SENT = new EventType("SENT"); + + public static final EventType IDLE = new EventType("IDLE"); + + public static final EventType EXCEPTION = new EventType("EXCEPTION"); + + private final String value; + + private EventType(String value) + { + this.value = value; + } + + public String toString() + { + return value; + } + } + + protected static class Event + { + private final EventType type; + private final NextFilter nextFilter; + private final Object data; + + public Event(EventType type, NextFilter nextFilter, Object data) + { + this.type = type; + this.nextFilter = nextFilter; + this.data = data; + } + + public Object getData() + { + return data; + } + + + public NextFilter getNextFilter() + { + return nextFilter; + } + + + public EventType getType() + { + return type; + } + } + + public void sessionCreated(NextFilter nextFilter, IoSession session) + { + nextFilter.sessionCreated(session); + } + + public void sessionOpened(NextFilter nextFilter, + IoSession session) + { + fireEvent(nextFilter, session, EventType.OPENED, null); + } + + public void sessionClosed(NextFilter nextFilter, + IoSession session) + { + fireEvent(nextFilter, session, EventType.CLOSED, null); + } + + public void sessionIdle(NextFilter nextFilter, + IoSession session, IdleStatus status) + { + fireEvent(nextFilter, session, EventType.IDLE, status); + } + + public void exceptionCaught(NextFilter nextFilter, + IoSession session, Throwable cause) + { + fireEvent(nextFilter, session, EventType.EXCEPTION, cause); + } + + public void messageReceived(NextFilter nextFilter, + IoSession session, Object message) + { + ByteBufferUtil.acquireIfPossible(message); + fireEvent(nextFilter, session, EventType.RECEIVED, message); + } + + public void messageSent(NextFilter nextFilter, + IoSession session, Object message) + { + ByteBufferUtil.acquireIfPossible(message); + fireEvent(nextFilter, session, EventType.SENT, message); + } + + protected void processEvent(NextFilter nextFilter, + IoSession session, EventType type, + Object data) + { + if (type == EventType.RECEIVED) + { + nextFilter.messageReceived(session, data); + ByteBufferUtil.releaseIfPossible(data); + } + else if (type == EventType.SENT) + { + nextFilter.messageSent(session, data); + ByteBufferUtil.releaseIfPossible(data); + } + else if (type == EventType.EXCEPTION) + { + nextFilter.exceptionCaught(session, (Throwable) data); + } + else if (type == EventType.IDLE) + { + nextFilter.sessionIdle(session, (IdleStatus) data); + } + else if (type == EventType.OPENED) + { + nextFilter.sessionOpened(session); + } + else if (type == EventType.CLOSED) + { + nextFilter.sessionClosed(session); + } + } + + public void filterWrite(NextFilter nextFilter, IoSession session, WriteRequest writeRequest) + { + nextFilter.filterWrite(session, writeRequest); + } + + public void filterClose(NextFilter nextFilter, IoSession session) throws Exception + { + nextFilter.filterClose(session); + } +} \ No newline at end of file diff --git a/java/broker/src/main/java/org/apache/qpid/server/txn/TxnBuffer.java b/java/broker/src/main/java/org/apache/qpid/server/txn/TxnBuffer.java new file mode 100644 index 0000000000..402065d5e1 --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/txn/TxnBuffer.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.server.txn; + +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.server.store.MessageStore; + +import java.util.ArrayList; +import java.util.List; + +/** + * Holds a list of TxnOp instance representing transactional + * operations. + */ +public class TxnBuffer +{ + private boolean _containsPersistentChanges = false; + private final MessageStore _store; + private final List _ops = new ArrayList(); + private static final Logger _log = Logger.getLogger(TxnBuffer.class); + + public TxnBuffer(MessageStore store) + { + _store = store; + } + + public void containsPersistentChanges() + { + _containsPersistentChanges = true; + } + + public void commit() throws AMQException + { + if (_containsPersistentChanges) + { + _log.debug("Begin Transaction."); + _store.beginTran(); + if(prepare()) + { + _log.debug("Transaction Succeeded"); + _store.commitTran(); + for (TxnOp op : _ops) + { + op.commit(); + } + } + else + { + _log.debug("Transaction Failed"); + _store.abortTran(); + } + }else{ + if(prepare()) + { + for (TxnOp op : _ops) + { + op.commit(); + } + } + } + _ops.clear(); + } + + private boolean prepare() + { + for (int i = 0; i < _ops.size(); i++) + { + TxnOp op = _ops.get(i); + try + { + op.prepare(); + } + catch(Exception e) + { + //compensate previously prepared ops + for(int j = 0; j < i; j++) + { + _ops.get(j).undoPrepare(); + } + return false; + } + } + return true; + } + + public void rollback() throws AMQException + { + for (TxnOp op : _ops) + { + op.rollback(); + } + _ops.clear(); + } + + public void enlist(TxnOp op) + { + _ops.add(op); + } + + public void cancel(TxnOp op) + { + _ops.remove(op); + } +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/txn/TxnOp.java b/java/broker/src/main/java/org/apache/qpid/server/txn/TxnOp.java new file mode 100644 index 0000000000..e863bab73e --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/txn/TxnOp.java @@ -0,0 +1,54 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.txn; + +import org.apache.qpid.AMQException; + +/** + * This provides the abstraction of an individual operation within a + * transaction. It is used by the TxnBuffer class. + */ +public interface TxnOp +{ + /** + * Do the part of the operation that updates persistent state + */ + public void prepare() throws AMQException; + /** + * Complete the operation started by prepare. Can now update in + * memory state or make netork transfers. + */ + public void commit(); + /** + * This is not the same as rollback. Unfortunately the use of an + * in memory reference count as a locking mechanism and a test for + * whether a message should be deleted means that as things are, + * handling an acknowledgement unavoidably alters both memory and + * persistent state on prepare. This is needed to 'compensate' or + * undo the in-memory change if the peristent update of later ops + * fails. + */ + public void undoPrepare(); + /** + * Rolls back the operation. + */ + public void rollback(); +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/util/CircularBuffer.java b/java/broker/src/main/java/org/apache/qpid/server/util/CircularBuffer.java new file mode 100644 index 0000000000..4767844abe --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/util/CircularBuffer.java @@ -0,0 +1,126 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.util; + +import java.util.Iterator; + +public class CircularBuffer implements Iterable +{ + private final Object[] _log; + private int _size; + private int _index; + + public CircularBuffer(int size) + { + _log = new Object[size]; + } + + public void add(Object o) + { + _log[_index++] = o; + _size = Math.min(_size+1, _log.length); + if(_index >= _log.length) + { + _index = 0; + } + } + + public Object get(int i) + { + if(i >= _log.length) + { + throw new ArrayIndexOutOfBoundsException(i); + } + return _log[index(i)]; + } + + public int size() { + return _size; + } + + public Iterator iterator() + { + return new Iterator() + { + private int i = 0; + + public boolean hasNext() + { + return i < _size; + } + + public Object next() + { + return get(i++); + } + + public void remove() + { + throw new UnsupportedOperationException(); + } + }; + } + + public String toString() + { + StringBuilder s = new StringBuilder(); + boolean first = true; + for(Object o : this) + { + if(!first) + { + s.append(", "); + } + else + { + first = false; + } + s.append(o); + } + return s.toString(); + } + + public void dump() + { + for(Object o : this) + { + System.out.println(o); + } + } + + int index(int i) + { + return _size == _log.length ? (_index + i) % _log.length : i; + } + + public static void main(String[] artgv) + { + String[] items = new String[]{ + "A","B","C","D","E","F","G","H","I","J","K" + }; + CircularBuffer buffer = new CircularBuffer(5); + for(String s : items) + { + buffer.add(s); + System.out.println(buffer); + } + } +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/util/ConcurrentLinkedQueueNoSize.java b/java/broker/src/main/java/org/apache/qpid/server/util/ConcurrentLinkedQueueNoSize.java new file mode 100644 index 0000000000..cf5e71a6e2 --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/util/ConcurrentLinkedQueueNoSize.java @@ -0,0 +1,38 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.util; + +import java.util.concurrent.ConcurrentLinkedQueue; + +public class ConcurrentLinkedQueueNoSize extends ConcurrentLinkedQueue +{ + public int size() + { + if (isEmpty()) + { + return 0; + } + else + { + return 1; + } + } +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/util/LoggingProxy.java b/java/broker/src/main/java/org/apache/qpid/server/util/LoggingProxy.java new file mode 100644 index 0000000000..eda97e0ed2 --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/util/LoggingProxy.java @@ -0,0 +1,105 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.util; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.util.Arrays; + +/** + * Dynamic proxy that records invocations in a fixed size circular buffer, + * dumping details on hitting an exception. + *

    + * Useful in debugging. + *

    + */ +public class LoggingProxy implements InvocationHandler +{ + private final Object _target; + private final CircularBuffer _log; + + public LoggingProxy(Object target, int size) + { + _target = target; + _log = new CircularBuffer(size); + } + + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable + { + try + { + entered(method, args); + Object result = method.invoke(_target, args); + returned(method, result); + return result; + } + catch(InvocationTargetException e) + { + dump(); + throw e.getTargetException(); + } + } + + void dump() + { + _log.dump(); + } + + CircularBuffer getBuffer() + { + return _log; + } + + private synchronized void entered(Method method, Object[] args) + { + if (args == null) + { + _log.add(Thread.currentThread() + ": " + method.getName() + "() entered"); + } + else + { + _log.add(Thread.currentThread() + ": " + method.getName() + "(" + Arrays.toString(args) + ") entered"); + } + } + + private synchronized void returned(Method method, Object result) + { + if (method.getReturnType() == Void.TYPE) + { + _log.add(Thread.currentThread() + ": " + method.getName() + "() returned"); + } + else + { + _log.add(Thread.currentThread() + ": " + method.getName() + "() returned " + result); + } + } + + public Object getProxy(Class... c) + { + return Proxy.newProxyInstance(_target.getClass().getClassLoader(), c, this); + } + + public int getBufferSize() { + return _log.size(); + } +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/util/NullApplicationRegistry.java b/java/broker/src/main/java/org/apache/qpid/server/util/NullApplicationRegistry.java new file mode 100644 index 0000000000..2e77f33363 --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/util/NullApplicationRegistry.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.server.util; + +import org.apache.qpid.server.exchange.DefaultExchangeFactory; +import org.apache.qpid.server.exchange.DefaultExchangeRegistry; +import org.apache.qpid.server.exchange.ExchangeFactory; +import org.apache.qpid.server.exchange.ExchangeRegistry; +import org.apache.qpid.server.management.ManagedObjectRegistry; +import org.apache.qpid.server.management.NoopManagedObjectRegistry; +import org.apache.qpid.server.queue.DefaultQueueRegistry; +import org.apache.qpid.server.queue.QueueRegistry; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.security.auth.AuthenticationManager; +import org.apache.qpid.server.security.auth.NullAuthenticationManager; +import org.apache.qpid.server.store.MessageStore; +import org.apache.qpid.server.store.MemoryMessageStore; +import org.apache.commons.configuration.Configuration; +import org.apache.commons.configuration.MapConfiguration; + +import java.util.HashMap; + +public class NullApplicationRegistry extends ApplicationRegistry +{ + private QueueRegistry _queueRegistry; + + private ExchangeRegistry _exchangeRegistry; + + private ExchangeFactory _exchangeFactory; + + private ManagedObjectRegistry _managedObjectRegistry; + + private AuthenticationManager _authenticationManager; + + private MessageStore _messageStore; + + + public NullApplicationRegistry() + { + super(new MapConfiguration(new HashMap())); + } + + public void initialise() throws Exception + { + _managedObjectRegistry = new NoopManagedObjectRegistry(); + _queueRegistry = new DefaultQueueRegistry(); + _exchangeFactory = new DefaultExchangeFactory(); + _exchangeRegistry = new DefaultExchangeRegistry(_exchangeFactory); + _authenticationManager = new NullAuthenticationManager(); + _messageStore = new MemoryMessageStore(); + ((MemoryMessageStore)_messageStore).configure(); + + _configuration.addProperty("heartbeat.delay", 10 * 60); // 10 minutes + } + + public Configuration getConfiguration() + { + return _configuration; + } + + public QueueRegistry getQueueRegistry() + { + return _queueRegistry; + } + + public ExchangeRegistry getExchangeRegistry() + { + return _exchangeRegistry; + } + + public ExchangeFactory getExchangeFactory() + { + return _exchangeFactory; + } + + public ManagedObjectRegistry getManagedObjectRegistry() + { + return _managedObjectRegistry; + } + + public AuthenticationManager getAuthenticationManager() + { + return _authenticationManager; + } + + public MessageStore getMessageStore() + { + return _messageStore; + } +} + diff --git a/java/broker/src/org/apache/qpid/server/AMQChannel.java b/java/broker/src/org/apache/qpid/server/AMQChannel.java deleted file mode 100644 index a6cb4523cf..0000000000 --- a/java/broker/src/org/apache/qpid/server/AMQChannel.java +++ /dev/null @@ -1,788 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server; - -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQDataBlock; -import org.apache.qpid.framing.BasicPublishBody; -import org.apache.qpid.framing.ContentBody; -import org.apache.qpid.framing.ContentHeaderBody; -import org.apache.qpid.server.ack.TxAck; -import org.apache.qpid.server.ack.UnacknowledgedMessage; -import org.apache.qpid.server.ack.UnacknowledgedMessageMap; -import org.apache.qpid.server.ack.UnacknowledgedMessageMapImpl; -import org.apache.qpid.server.exchange.MessageRouter; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.queue.AMQMessage; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.queue.NoConsumersException; -import org.apache.qpid.server.store.MessageStore; -import org.apache.qpid.server.txn.TxnBuffer; -import org.apache.qpid.server.txn.TxnOp; - -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.TreeMap; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicLong; - -public class AMQChannel -{ - public static final int DEFAULT_PREFETCH = 5000; - - private static final Logger _log = Logger.getLogger(AMQChannel.class); - - private final int _channelId; - - private boolean _transactional; - - private long _prefetch_HighWaterMark; - - private long _prefetch_LowWaterMark; - - /** - * The delivery tag is unique per channel. This is pre-incremented before putting into the deliver frame so that - * value of this represents the last tag sent out - */ - private AtomicLong _deliveryTag = new AtomicLong(0); - - /** - * A channel has a default queue (the last declared) that is used when no queue name is - * explictily set - */ - private AMQQueue _defaultQueue; - - /** - * This tag is unique per subscription to a queue. The server returns this in response to a - * basic.consume request. - */ - private int _consumerTag; - - /** - * The current message - which may be partial in the sense that not all frames have been received yet - - * which has been received by this channel. As the frames are received the message gets updated and once all - * frames have been received the message can then be routed. - */ - private AMQMessage _currentMessage; - - /** - * Maps from consumer tag to queue instance. Allows us to unsubscribe from a queue. - */ - private final Map _consumerTag2QueueMap = new TreeMap(); - - private final MessageStore _messageStore; - - private final Object _unacknowledgedMessageMapLock = new Object(); - - private Map _unacknowledgedMessageMap = new LinkedHashMap(DEFAULT_PREFETCH); - - private long _lastDeliveryTag; - - private final AtomicBoolean _suspended = new AtomicBoolean(false); - - private final MessageRouter _exchanges; - - private final TxnBuffer _txnBuffer; - - private TxAck ackOp; - - private final List _returns = new LinkedList(); - - public AMQChannel(int channelId, MessageStore messageStore, MessageRouter exchanges) - throws AMQException - { - _channelId = channelId; - _prefetch_HighWaterMark = DEFAULT_PREFETCH; - _prefetch_LowWaterMark = _prefetch_HighWaterMark / 2; - _messageStore = messageStore; - _exchanges = exchanges; - _txnBuffer = new TxnBuffer(_messageStore); - } - - public int getChannelId() - { - return _channelId; - } - - public boolean isTransactional() - { - return _transactional; - } - - public void setTransactional(boolean transactional) - { - _transactional = transactional; - } - - public long getPrefetchCount() - { - return _prefetch_HighWaterMark; - } - - public void setPrefetchCount(long prefetchCount) - { - _prefetch_HighWaterMark = prefetchCount; - } - - public long getPrefetchLowMarkCount() - { - return _prefetch_LowWaterMark; - } - - public void setPrefetchLowMarkCount(long prefetchCount) - { - _prefetch_LowWaterMark = prefetchCount; - } - - public long getPrefetchHighMarkCount() - { - return _prefetch_HighWaterMark; - } - - public void setPrefetchHighMarkCount(long prefetchCount) - { - _prefetch_HighWaterMark = prefetchCount; - } - - - public void setPublishFrame(BasicPublishBody publishBody, AMQProtocolSession publisher) throws AMQException - { - _currentMessage = new AMQMessage(_messageStore, publishBody); - _currentMessage.setPublisher(publisher); - } - - public void publishContentHeader(ContentHeaderBody contentHeaderBody) - throws AMQException - { - if (_currentMessage == null) - { - throw new AMQException("Received content header without previously receiving a BasicDeliver frame"); - } - else - { - _currentMessage.setContentHeaderBody(contentHeaderBody); - // check and route if header says body length is zero - if (contentHeaderBody.bodySize == 0) - { - routeCurrentMessage(); - } - } - } - - public void publishContentBody(ContentBody contentBody) - throws AMQException - { - if (_currentMessage == null) - { - throw new AMQException("Received content body without previously receiving a JmsPublishBody"); - } - if (_currentMessage.getContentHeaderBody() == null) - { - throw new AMQException("Received content body without previously receiving a content header"); - } - - _currentMessage.addContentBodyFrame(contentBody); - if (_currentMessage.isAllContentReceived()) - { - routeCurrentMessage(); - } - } - - protected void routeCurrentMessage() throws AMQException - { - if (_transactional) - { - //don't create a transaction unless needed - if (_currentMessage.isPersistent()) - { - _txnBuffer.containsPersistentChanges(); - } - - //A publication will result in the enlisting of several - //TxnOps. The first is an op that will store the message. - //Following that (and ordering is important), an op will - //be added for every queue onto which the message is - //enqueued. Finally a cleanup op will be added to decrement - //the reference associated with the routing. - Store storeOp = new Store(_currentMessage); - _txnBuffer.enlist(storeOp); - _currentMessage.setTxnBuffer(_txnBuffer); - try - { - _exchanges.routeContent(_currentMessage); - _txnBuffer.enlist(new Cleanup(_currentMessage)); - } - catch (RequiredDeliveryException e) - { - //Can only be due to the mandatory flag, as no attempt - //has yet been made to deliver the message. The - //message will thus not have been delivered to any - //queue so we can return the message (without killing - //the transaction) and for efficiency remove the store - //operation from the buffer. - _txnBuffer.cancel(storeOp); - throw e; - } - finally - { - _currentMessage = null; - } - } - else - { - try - { - _exchanges.routeContent(_currentMessage); - //following check implements the functionality - //required by the 'immediate' flag: - _currentMessage.checkDeliveredToConsumer(); - } - finally - { - _currentMessage.decrementReference(); - _currentMessage = null; - } - } - } - - public long getNextDeliveryTag() - { - return _deliveryTag.incrementAndGet(); - } - - public int getNextConsumerTag() - { - return ++_consumerTag; - } - - /** - * Subscribe to a queue. We register all subscriptions in the channel so that - * if the channel is closed we can clean up all subscriptions, even if the - * client does not explicitly unsubscribe from all queues. - * - * @param tag the tag chosen by the client (if null, server will generate one) - * @param queue the queue to subscribe to - * @param session the protocol session of the subscriber - * @return the consumer tag. This is returned to the subscriber and used in - * subsequent unsubscribe requests - * @throws ConsumerTagNotUniqueException if the tag is not unique - * @throws AMQException if something goes wrong - */ - public String subscribeToQueue(String tag, AMQQueue queue, AMQProtocolSession session, boolean acks) throws AMQException, ConsumerTagNotUniqueException - { - if (tag == null) - { - tag = "sgen_" + getNextConsumerTag(); - } - if (_consumerTag2QueueMap.containsKey(tag)) - { - throw new ConsumerTagNotUniqueException(); - } - - queue.registerProtocolSession(session, _channelId, tag, acks); - _consumerTag2QueueMap.put(tag, queue); - return tag; - } - - - public void unsubscribeConsumer(AMQProtocolSession session, String consumerTag) throws AMQException - { - AMQQueue q = _consumerTag2QueueMap.remove(consumerTag); - if (q != null) - { - q.unregisterProtocolSession(session, _channelId, consumerTag); - } - } - - /** - * Called from the protocol session to close this channel and clean up. - * - * @throws AMQException if there is an error during closure - */ - public void close(AMQProtocolSession session) throws AMQException - { - if (_transactional) - { - synchronized(_txnBuffer) - { - _txnBuffer.rollback();//releases messages - } - } - unsubscribeAllConsumers(session); - requeue(); - } - - private void unsubscribeAllConsumers(AMQProtocolSession session) throws AMQException - { - _log.info("Unsubscribing all consumers on channel " + toString()); - for (Map.Entry me : _consumerTag2QueueMap.entrySet()) - { - me.getValue().unregisterProtocolSession(session, _channelId, me.getKey()); - } - _consumerTag2QueueMap.clear(); - } - - /** - * Add a message to the channel-based list of unacknowledged messages - * - * @param message - * @param deliveryTag - * @param queue - */ - public void addUnacknowledgedMessage(AMQMessage message, long deliveryTag, String consumerTag, AMQQueue queue) - { - synchronized(_unacknowledgedMessageMapLock) - { - _unacknowledgedMessageMap.put(deliveryTag, new UnacknowledgedMessage(queue, message, consumerTag, deliveryTag)); - _lastDeliveryTag = deliveryTag; - checkSuspension(); - } - } - - /** - * Called to attempt re-enqueue all outstanding unacknowledged messages on the channel. - * May result in delivery to this same channel or to other subscribers. - */ - public void requeue() throws AMQException - { - // we must create a new map since all the messages will get a new delivery tag when they are redelivered - Map currentList; - synchronized(_unacknowledgedMessageMapLock) - { - currentList = _unacknowledgedMessageMap; - _unacknowledgedMessageMap = new LinkedHashMap(DEFAULT_PREFETCH); - } - - for (UnacknowledgedMessage unacked : currentList.values()) - { - if (unacked.queue != null) - { - unacked.queue.deliver(unacked.message); - } - } - } - - /** - * Called to resend all outstanding unacknowledged messages to this same channel. - */ - public void resend(AMQProtocolSession session) - { - //messages go to this channel - synchronized(_unacknowledgedMessageMapLock) - { - for (Map.Entry entry : _unacknowledgedMessageMap.entrySet()) - { - long deliveryTag = entry.getKey(); - String consumerTag = entry.getValue().consumerTag; - AMQMessage msg = entry.getValue().message; - - session.writeFrame(msg.getDataBlock(_channelId, consumerTag, deliveryTag)); - } - } - } - - /** - * Callback indicating that a queue has been deleted. We must update the structure of unacknowledged - * messages to remove the queue reference and also decrement any message reference counts, without - * actually removing the item sine we may get an ack for a delivery tag that was generated from the - * deleted queue. - * - * @param queue - */ - public void queueDeleted(AMQQueue queue) - { - synchronized(_unacknowledgedMessageMapLock) - { - for (Map.Entry unacked : _unacknowledgedMessageMap.entrySet()) - { - final UnacknowledgedMessage unackedMsg = unacked.getValue(); - // we can compare the reference safely in this case - if (unackedMsg.queue == queue) - { - unackedMsg.queue = null; - try - { - unackedMsg.message.decrementReference(); - } - catch (AMQException e) - { - _log.error("Error decrementing ref count on message " + unackedMsg.message.getMessageId() + ": " + - e, e); - } - } - } - } - } - - /** - * Acknowledge one or more messages. - * - * @param deliveryTag the last delivery tag - * @param multiple if true will acknowledge all messages up to an including the delivery tag. if false only - * acknowledges the single message specified by the delivery tag - * @throws AMQException if the delivery tag is unknown (e.g. not outstanding) on this channel - */ - public void acknowledgeMessage(long deliveryTag, boolean multiple) throws AMQException - { - if (_transactional) - { - //check that the tag exists to give early failure - if (!multiple || deliveryTag > 0) - { - checkAck(deliveryTag); - } - //we use a single txn op for all acks and update this op - //as new acks come in. If this is the first ack in the txn - //we will need to create and enlist the op. - if (ackOp == null) - { - ackOp = new TxAck(new AckMap()); - _txnBuffer.enlist(ackOp); - } - //update the op to include this ack request - if (multiple && deliveryTag == 0) - { - synchronized(_unacknowledgedMessageMapLock) - { - //if have signalled to ack all, that refers only - //to all at this time - ackOp.update(_lastDeliveryTag, multiple); - } - } - else - { - ackOp.update(deliveryTag, multiple); - } - } - else - { - handleAcknowledgement(deliveryTag, multiple); - } - } - - private void checkAck(long deliveryTag) throws AMQException - { - synchronized(_unacknowledgedMessageMapLock) - { - if (!_unacknowledgedMessageMap.containsKey(deliveryTag)) - { - throw new AMQException("Ack with delivery tag " + deliveryTag + " not known for channel"); - } - } - } - - private void handleAcknowledgement(long deliveryTag, boolean multiple) throws AMQException - { - if (multiple) - { - LinkedList acked = new LinkedList(); - synchronized(_unacknowledgedMessageMapLock) - { - if (deliveryTag == 0) - { - //Spec 2.1.6.11 ... If the multiple field is 1, and the delivery tag is zero, tells the server to acknowledge all outstanding mesages. - _log.trace("Multiple ack on delivery tag 0. ACKing all messages. Current count:" + _unacknowledgedMessageMap.size()); - acked = new LinkedList(_unacknowledgedMessageMap.values()); - _unacknowledgedMessageMap.clear(); - } - else - { - if (!_unacknowledgedMessageMap.containsKey(deliveryTag)) - { - throw new AMQException("Multiple ack on delivery tag " + deliveryTag + " not known for channel"); - } - Iterator> i = _unacknowledgedMessageMap.entrySet().iterator(); - - while (i.hasNext()) - { - - Map.Entry unacked = i.next(); - - if (unacked.getKey() > deliveryTag) - { - //This should not occur now. - throw new AMQException("UnacknowledgedMessageMap is out of order:" + unacked.getKey() + " When deliveryTag is:" + deliveryTag + "ES:" + _unacknowledgedMessageMap.entrySet().toString()); - } - - i.remove(); - - acked.add(unacked.getValue()); - if (unacked.getKey() == deliveryTag) - { - break; - } - } - } - }// synchronized - - if (_log.isTraceEnabled()) - { - _log.trace("Received multiple ack for delivery tag " + deliveryTag + ". Removing " + - acked.size() + " items."); - } - - for (UnacknowledgedMessage msg : acked) - { - msg.discard(); - } - - } - else - { - UnacknowledgedMessage msg; - synchronized(_unacknowledgedMessageMapLock) - { - msg = _unacknowledgedMessageMap.remove(deliveryTag); - } - - if (msg == null) - { - _log.trace("Single ack on delivery tag " + deliveryTag + " not known for channel:" + _channelId); - throw new AMQException("Single ack on delivery tag " + deliveryTag + " not known for channel:" + _channelId); - } - msg.discard(); - if (_log.isTraceEnabled()) - { - _log.trace("Received non-multiple ack for messaging with delivery tag " + deliveryTag); - } - } - - checkSuspension(); - } - - /** - * Used only for testing purposes. - * - * @return the map of unacknowledged messages - */ - public Map getUnacknowledgedMessageMap() - { - return _unacknowledgedMessageMap; - } - - private void checkSuspension() - { - boolean suspend; - //noinspection SynchronizeOnNonFinalField - synchronized(_unacknowledgedMessageMapLock) - { - suspend = _unacknowledgedMessageMap.size() >= _prefetch_HighWaterMark; - } - setSuspended(suspend); - } - - public void setSuspended(boolean suspended) - { - boolean isSuspended = _suspended.get(); - - if (isSuspended && !suspended) - { - synchronized(_unacknowledgedMessageMapLock) - { - // Continue being suspended if we are above the _prefetch_LowWaterMark - suspended = _unacknowledgedMessageMap.size() > _prefetch_LowWaterMark; - } - } - - boolean wasSuspended = _suspended.getAndSet(suspended); - if (wasSuspended != suspended) - { - if (wasSuspended) - { - _log.debug("Unsuspending channel " + this); - //may need to deliver queued messages - for (AMQQueue q : _consumerTag2QueueMap.values()) - { - q.deliverAsync(); - } - } - else - { - _log.debug("Suspending channel " + this); - } - } - } - - public boolean isSuspended() - { - return _suspended.get(); - } - - public void commit() throws AMQException - { - if (ackOp != null) - { - ackOp.consolidate(); - if (ackOp.checkPersistent()) - { - _txnBuffer.containsPersistentChanges(); - } - ackOp = null;//already enlisted, after commit will reset regardless of outcome - } - - _txnBuffer.commit(); - //TODO: may need to return 'immediate' messages at this point - } - - public void rollback() throws AMQException - { - //need to protect rollback and close from each other... - synchronized(_txnBuffer) - { - _txnBuffer.rollback(); - } - } - - public String toString() - { - StringBuilder sb = new StringBuilder(30); - sb.append("Channel: id ").append(_channelId).append(", transaction mode: ").append(_transactional); - sb.append(", prefetch marks: ").append(_prefetch_LowWaterMark); - sb.append("/").append(_prefetch_HighWaterMark); - return sb.toString(); - } - - public void setDefaultQueue(AMQQueue queue) - { - _defaultQueue = queue; - } - - public AMQQueue getDefaultQueue() - { - return _defaultQueue; - } - - public void processReturns(AMQProtocolSession session) - { - for (AMQDataBlock block : _returns) - { - session.writeFrame(block); - } - _returns.clear(); - } - - //we use this wrapper to ensure we are always using the correct - //map instance (its not final unfortunately) - private class AckMap implements UnacknowledgedMessageMap - { - public void collect(long deliveryTag, boolean multiple, List msgs) - { - impl().collect(deliveryTag, multiple, msgs); - } - - public void remove(List msgs) - { - impl().remove(msgs); - } - - private UnacknowledgedMessageMap impl() - { - return new UnacknowledgedMessageMapImpl(_unacknowledgedMessageMapLock, _unacknowledgedMessageMap); - } - } - - private class Store implements TxnOp - { - //just use this to do a store of the message during the - //prepare phase. Any enqueueing etc is done by TxnOps enlisted - //by the queues themselves. - private final AMQMessage _msg; - - Store(AMQMessage msg) - { - _msg = msg; - } - - public void prepare() throws AMQException - { - _msg.storeMessage(); - //the routers reference can now be released - _msg.decrementReference(); - } - - public void undoPrepare() - { - } - - public void commit() - { - } - - public void rollback() - { - } - } - - private class Cleanup implements TxnOp - { - private final AMQMessage _msg; - - Cleanup(AMQMessage msg) - { - _msg = msg; - } - - public void prepare() throws AMQException - { - } - - public void undoPrepare() - { - //don't need to do anything here, if the store's txn failed - //when processing prepare then the message was not stored - //or enqueued on any queues and can be discarded - } - - public void commit() - { - //The routers reference can now be released. This is done - //here to ensure that it happens after the queues that - //enqueue it have incremented their counts (which as a - //memory only operation is done in the commit phase). - try - { - _msg.decrementReference(); - } - catch (AMQException e) - { - _log.error("On commiting transaction, failed to cleanup unused message: " + e, e); - } - try - { - _msg.checkDeliveredToConsumer(); - } - catch (NoConsumersException e) - { - //TODO: store this for delivery after the commit-ok - _returns.add(e.getReturnMessage(_channelId)); - } - } - - public void rollback() - { - } - } - -} diff --git a/java/broker/src/org/apache/qpid/server/ConsumerTagNotUniqueException.java b/java/broker/src/org/apache/qpid/server/ConsumerTagNotUniqueException.java deleted file mode 100644 index 9a98af5689..0000000000 --- a/java/broker/src/org/apache/qpid/server/ConsumerTagNotUniqueException.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server; - -public class ConsumerTagNotUniqueException extends Exception -{ -} diff --git a/java/broker/src/org/apache/qpid/server/Main.java b/java/broker/src/org/apache/qpid/server/Main.java deleted file mode 100644 index d2dacb6140..0000000000 --- a/java/broker/src/org/apache/qpid/server/Main.java +++ /dev/null @@ -1,627 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server; - -import org.apache.qpid.framing.ProtocolVersionList; -import org.apache.qpid.pool.ReadWriteThreadModel; -import org.apache.qpid.server.protocol.AMQPFastProtocolHandler; -import org.apache.qpid.server.protocol.AMQPProtocolProvider; -import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.registry.ConfigurationFileApplicationRegistry; -import org.apache.qpid.server.registry.IApplicationRegistry; -import org.apache.qpid.server.transport.ConnectorConfiguration; -import org.apache.qpid.server.configuration.VirtualHostConfiguration; -import org.apache.qpid.server.management.*; -import org.apache.qpid.server.queue.QueueRegistry; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.exchange.ExchangeRegistry; -import org.apache.qpid.server.exchange.ExchangeFactory; -import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.server.store.MessageStore; -import org.apache.qpid.AMQException; -import org.apache.qpid.url.URLSyntaxException; -import org.apache.commons.cli.*; -import org.apache.commons.configuration.ConfigurationException; -import org.apache.log4j.BasicConfigurator; -import org.apache.log4j.Logger; -import org.apache.log4j.xml.DOMConfigurator; -import org.apache.mina.common.ByteBuffer; -import org.apache.mina.common.IoAcceptor; -import org.apache.mina.common.SimpleByteBufferAllocator; -import org.apache.mina.transport.socket.nio.SocketSessionConfig; - -import javax.management.JMException; -import javax.management.MBeanException; -import javax.management.NotCompliantMBeanException; -import javax.management.ObjectName; -import javax.management.MalformedObjectNameException; - -import java.io.File; -import java.io.IOException; -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.util.StringTokenizer; -import java.util.Collection; -import java.util.List; - -/** - * Main entry point for AMQPD. - */ -public class Main implements ProtocolVersionList -{ - private static final Logger _logger = Logger.getLogger(Main.class); - - private static final String DEFAULT_CONFIG_FILE = "etc/config.xml"; - - private static final String DEFAULT_LOG_CONFIG_FILENAME = "log4j.xml"; - - protected static class InitException extends Exception - { - InitException(String msg) - { - super(msg); - } - } - - protected final Options options = new Options(); - protected CommandLine commandLine; - - protected Main(String[] args) - { - setOptions(options); - if (parseCommandline(args)) - { - execute(); - } - } - - protected boolean parseCommandline(String[] args) - { - try - { - commandLine = new PosixParser().parse(options, args); - return true; - } - catch (ParseException e) - { - System.err.println("Error: " + e.getMessage()); - HelpFormatter formatter = new HelpFormatter(); - formatter.printHelp("Qpid", options, true); - return false; - } - } - - protected void setOptions(Options options) - { - Option help = new Option("h", "help", false, "print this message"); - Option version = new Option("v", "version", false, "print the version information and exit"); - Option configFile = OptionBuilder.withArgName("file").hasArg().withDescription("use given configuration file"). - withLongOpt("config").create("c"); - Option port = OptionBuilder.withArgName("port").hasArg().withDescription("listen on the specified port. Overrides any value in the config file"). - withLongOpt("port").create("p"); - Option bind = OptionBuilder.withArgName("bind").hasArg().withDescription("bind to the specified address. Overrides any value in the config file"). - withLongOpt("bind").create("b"); - Option logconfig = OptionBuilder.withArgName("logconfig").hasArg().withDescription("use the specified log4j xml configuration file. By " + - "default looks for a file named " + DEFAULT_LOG_CONFIG_FILENAME + " in the same directory as the configuration file"). - withLongOpt("logconfig").create("l"); - Option logwatchconfig = OptionBuilder.withArgName("logwatch").hasArg().withDescription("monitor the log file configuration file for changes. Units are seconds. " + - "Zero means do not check for changes.").withLongOpt("logwatch").create("w"); - - options.addOption(help); - options.addOption(version); - options.addOption(configFile); - options.addOption(logconfig); - options.addOption(logwatchconfig); - options.addOption(port); - options.addOption(bind); - } - - protected void execute() - { - // note this understands either --help or -h. If an option only has a long name you can use that but if - // an option has a short name and a long name you must use the short name here. - if (commandLine.hasOption("h")) - { - HelpFormatter formatter = new HelpFormatter(); - formatter.printHelp("Qpid", options, true); - } - else if (commandLine.hasOption("v")) - { - String ver = "Qpid 0.9.0.0"; - String protocol = "AMQP version(s) [major.minor]: "; - for (int i = 0; i < pv.length; i++) - { - if (i > 0) - { - protocol += ", "; - } - protocol += pv[i][PROTOCOL_MAJOR] + "." + pv[i][PROTOCOL_MINOR]; - } - System.out.println(ver + " (" + protocol + ")"); - } - else - { - try - { - startup(); - } - catch (InitException e) - { - System.out.println(e.getMessage()); - } - catch (ConfigurationException e) - { - System.out.println("Error configuring message broker: " + e); - e.printStackTrace(); - } - catch (Exception e) - { - System.out.println("Error intialising message broker: " + e); - e.printStackTrace(); - } - } - } - - - protected void startup() throws InitException, ConfigurationException, Exception - { - final String QpidHome = System.getProperty("QPID_HOME"); - final File defaultConfigFile = new File(QpidHome, DEFAULT_CONFIG_FILE); - final File configFile = new File(commandLine.getOptionValue("c", defaultConfigFile.getPath())); - if (!configFile.exists()) - { - String error = "File " + configFile + " could not be found. Check the file exists and is readable."; - - if (QpidHome == null) - { - error = error + "\nNote: Qpid_HOME is not set."; - } - - throw new InitException(error); - } - else - { - System.out.println("Using configuration file " + configFile.getAbsolutePath()); - } - - String logConfig = commandLine.getOptionValue("l"); - String logWatchConfig = commandLine.getOptionValue("w", "0"); - if (logConfig != null) - { - File logConfigFile = new File(logConfig); - configureLogging(logConfigFile, logWatchConfig); - } - else - { - File configFileDirectory = configFile.getParentFile(); - File logConfigFile = new File(configFileDirectory, DEFAULT_LOG_CONFIG_FILENAME); - configureLogging(logConfigFile, logWatchConfig); - } - - ApplicationRegistry.initialise(new ConfigurationFileApplicationRegistry(configFile)); - - _logger.info("Starting Qpid.AMQP broker"); - - ConnectorConfiguration connectorConfig = ApplicationRegistry.getInstance(). - getConfiguredObject(ConnectorConfiguration.class); - - // From old Mina - //ByteBuffer.setUseDirectBuffers(connectorConfig.enableDirectBuffers); - - // the MINA default is currently to use the pooled allocator although this may change in future - // once more testing of the performance of the simple allocator has been done - if (!connectorConfig.enablePooledAllocator) - { - ByteBuffer.setAllocator(new SimpleByteBufferAllocator()); - } - - int port = connectorConfig.port; - - String portStr = commandLine.getOptionValue("p"); - if (portStr != null) - { - try - { - port = Integer.parseInt(portStr); - } - catch (NumberFormatException e) - { - throw new InitException("Invalid port: " + portStr); - } - } - - String VIRTUAL_HOSTS = "virtualhosts"; - - Object virtualHosts = ApplicationRegistry.getInstance().getConfiguration().getProperty(VIRTUAL_HOSTS); - - if (virtualHosts != null) - { - if (virtualHosts instanceof Collection) - { - int totalVHosts = ((Collection) virtualHosts).size(); - for (int vhost = 0; vhost < totalVHosts; vhost++) - { - setupVirtualHosts(configFile.getParent(), (String) ((List) virtualHosts).get(vhost)); - } - } - else - { - setupVirtualHosts(configFile.getParent(), (String) virtualHosts); - } - } - bind(port, connectorConfig); - - createAndRegisterBrokerMBean(); - } - - protected void setupVirtualHosts(String configFileParent, String configFilePath) throws ConfigurationException, AMQException, URLSyntaxException - { - String configVar = "${conf}"; - - if (configFilePath.startsWith(configVar)) - { - configFilePath = configFileParent + configFilePath.substring(configVar.length()); - } - - if (configFilePath.indexOf(".xml") != -1) - { - VirtualHostConfiguration vHostConfig = new VirtualHostConfiguration(configFilePath); - vHostConfig.performBindings(); - } - else - { - // the virtualhosts value is a path. Search it for XML files. - - File virtualHostDir = new File(configFilePath); - - String[] fileNames = virtualHostDir.list(); - - for (int each = 0; each < fileNames.length; each++) - { - if (fileNames[each].endsWith(".xml")) - { - VirtualHostConfiguration vHostConfig = new VirtualHostConfiguration(configFilePath + "/" + fileNames[each]); - vHostConfig.performBindings(); - } - } - } - } - - protected void bind(int port, ConnectorConfiguration connectorConfig) - { - String bindAddr = commandLine.getOptionValue("b"); - if (bindAddr == null) - { - bindAddr = connectorConfig.bindAddress; - } - - try - { - //IoAcceptor acceptor = new SocketAcceptor(connectorConfig.processors); - IoAcceptor acceptor = connectorConfig.createAcceptor(); - - SocketSessionConfig sc; - - sc = (SocketSessionConfig) acceptor.getSessionConfig(); - - sc.setReceiveBufferSize(connectorConfig.socketReceiveBufferSize); - sc.setSendBufferSize(connectorConfig.socketWriteBuferSize); - sc.setTcpNoDelay(connectorConfig.tcpNoDelay); - - // if we do not use the executor pool threading model we get the default leader follower - // implementation provided by MINA - if (connectorConfig.enableExecutorPool) - { - acceptor.setThreadModel(new ReadWriteThreadModel()); - } - - if (connectorConfig.enableNonSSL) - { - AMQPFastProtocolHandler handler = new AMQPProtocolProvider().getHandler(); - InetSocketAddress bindAddress; - if (bindAddr.equals("wildcard")) - { - bindAddress = new InetSocketAddress(port); - } - else - { - bindAddress = new InetSocketAddress(InetAddress.getByAddress(parseIP(bindAddr)), port); - } - acceptor.setLocalAddress(bindAddress); - acceptor.setHandler(handler); - acceptor.bind(); - _logger.info("Qpid.AMQP listening on non-SSL address " + bindAddress); - } - - if (connectorConfig.enableSSL) - { - AMQPFastProtocolHandler handler = new AMQPProtocolProvider().getHandler(); - handler.setUseSSL(true); - try - { - acceptor.setLocalAddress(new InetSocketAddress(connectorConfig.sslPort)); - acceptor.setHandler(handler); - acceptor.bind(); - _logger.info("Qpid.AMQP listening on SSL port " + connectorConfig.sslPort); - } - catch (IOException e) - { - _logger.error("Unable to listen on SSL port: " + e, e); - } - } - } - catch (Exception e) - { - _logger.error("Unable to bind service to registry: " + e, e); - } - } - - public static void main(String[] args) - { - - new Main(args); - } - - private byte[] parseIP(String address) throws Exception - { - StringTokenizer tokenizer = new StringTokenizer(address, "."); - byte[] ip = new byte[4]; - int index = 0; - while (tokenizer.hasMoreTokens()) - { - String token = tokenizer.nextToken(); - try - { - ip[index++] = Byte.parseByte(token); - } - catch (NumberFormatException e) - { - throw new Exception("Error parsing IP address: " + address, e); - } - } - if (index != 4) - { - throw new Exception("Invalid IP address: " + address); - } - return ip; - } - - private void configureLogging(File logConfigFile, String logWatchConfig) - { - int logWatchTime = 0; - try - { - logWatchTime = Integer.parseInt(logWatchConfig); - } - catch (NumberFormatException e) - { - System.err.println("Log watch configuration value of " + logWatchConfig + " is invalid. Must be " + - "a non-negative integer. Using default of zero (no watching configured"); - } - if (logConfigFile.exists() && logConfigFile.canRead()) - { - System.out.println("Configuring logger using configuration file " + logConfigFile.getAbsolutePath()); - - if (logWatchTime > 0) - { - System.out.println("log file " + logConfigFile.getAbsolutePath() + " will be checked for changes every " + - logWatchTime + " seconds"); - // log4j expects the watch interval in milliseconds - DOMConfigurator.configureAndWatch(logConfigFile.getAbsolutePath(), logWatchTime * 1000); - } - else - { - DOMConfigurator.configure(logConfigFile.getAbsolutePath()); - } - } - else - { - System.err.println("Logging configuration error: unable to read file " + logConfigFile.getAbsolutePath()); - System.err.println("Using basic log4j configuration"); - BasicConfigurator.configure(); - } - } - - private void createAndRegisterBrokerMBean() throws AMQException - { - try - { - new AMQBrokerManager().register(); - } - catch (NotCompliantMBeanException ex) - { - throw new AMQException("Exception occured in creating AMQBrokerManager MBean."); - } - } - - /** - * AMQPBrokerMBean implements the broker management interface and exposes the - * Broker level management features like creating and deleting exchanges and queue. - */ - @MBeanDescription("This MBean exposes the broker level management features") - private final class AMQBrokerManager extends AMQManagedObject - implements ManagedBroker - { - private final QueueRegistry _queueRegistry; - private final ExchangeRegistry _exchangeRegistry; - private final ExchangeFactory _exchangeFactory; - private final MessageStore _messageStore; - - @MBeanConstructor("Creates the Broker Manager MBean") - protected AMQBrokerManager() throws NotCompliantMBeanException - { - super(ManagedBroker.class, ManagedBroker.TYPE); - - IApplicationRegistry appRegistry = ApplicationRegistry.getInstance(); - _queueRegistry = appRegistry.getQueueRegistry(); - _exchangeRegistry = appRegistry.getExchangeRegistry(); - _exchangeFactory = ApplicationRegistry.getInstance().getExchangeFactory(); - _messageStore = ApplicationRegistry.getInstance().getMessageStore(); - } - - public String getObjectInstanceName() - { - return this.getClass().getName(); - } - - /** - * Creates new exchange and registers it with the registry. - * - * @param exchangeName - * @param type - * @param durable - * @param autoDelete - * @throws JMException - */ - public void createNewExchange(String exchangeName, - String type, - boolean durable, - boolean autoDelete) - throws JMException - { - try - { - synchronized(_exchangeRegistry) - { - Exchange exchange = _exchangeRegistry.getExchange(exchangeName); - - if (exchange == null) - { - exchange = _exchangeFactory.createExchange(exchangeName, - type, //eg direct - durable, - autoDelete, - 0); //ticket no - _exchangeRegistry.registerExchange(exchange); - } - else - { - throw new JMException("The exchange \"" + exchangeName + "\" already exists."); - } - } - } - catch (AMQException ex) - { - _logger.error("Error in creating exchange " + exchangeName, ex); - throw new MBeanException(ex, ex.toString()); - } - } - - /** - * Unregisters the exchange from registry. - * - * @param exchangeName - * @throws JMException - */ - public void unregisterExchange(String exchangeName) - throws JMException - { - boolean inUse = false; - // TODO - // Check if the exchange is in use. - // Check if there are queue-bindings with the exchnage and unregister - // when there are no bindings. - try - { - _exchangeRegistry.unregisterExchange(exchangeName, false); - } - catch (AMQException ex) - { - _logger.error("Error in unregistering exchange " + exchangeName, ex); - throw new MBeanException(ex, ex.toString()); - } - } - - /** - * Creates a new queue and registers it with the registry and puts it - * in persistance storage if durable queue. - * - * @param queueName - * @param durable - * @param owner - * @param autoDelete - * @throws JMException - */ - public void createQueue(String queueName, - boolean durable, - String owner, - boolean autoDelete) - throws JMException - { - AMQQueue queue = _queueRegistry.getQueue(queueName); - if (queue == null) - { - try - { - queue = new AMQQueue(queueName, durable, owner, autoDelete, _queueRegistry); - if (queue.isDurable() && !queue.isAutoDelete()) - { - _messageStore.createQueue(queue); - } - _queueRegistry.registerQueue(queue); - } - catch (AMQException ex) - { - _logger.error("Error in creating queue " + queueName, ex); - throw new MBeanException(ex, ex.toString()); - } - } - else - { - throw new JMException("The queue \"" + queueName + "\" already exists."); - } - } - - /** - * Deletes the queue from queue registry and persistant storage. - * - * @param queueName - * @throws JMException - */ - public void deleteQueue(String queueName) throws JMException - { - AMQQueue queue = _queueRegistry.getQueue(queueName); - if (queue == null) - { - throw new JMException("The Queue " + queueName + " is not a registerd queue."); - } - - try - { - queue.delete(); - _messageStore.removeQueue(queueName); - - } - catch (AMQException ex) - { - throw new MBeanException(ex, ex.toString()); - } - } - - public ObjectName getObjectName() throws MalformedObjectNameException - { - StringBuffer objectName = new StringBuffer(ManagedObject.DOMAIN); - objectName.append(":type=").append(getType()); - - return new ObjectName(objectName.toString()); - } - } // End of MBean class -} diff --git a/java/broker/src/org/apache/qpid/server/ManagedChannel.java b/java/broker/src/org/apache/qpid/server/ManagedChannel.java deleted file mode 100644 index 74c5366c7d..0000000000 --- a/java/broker/src/org/apache/qpid/server/ManagedChannel.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ - -package org.apache.qpid.server; - -import javax.management.JMException; -import java.io.IOException; - -/** - * The managed interface exposed to allow management of channels. - * @author Bhupendra Bhardwaj - * @version 0.1 - */ -public interface ManagedChannel -{ - static final String TYPE = "Channel"; - - /** - * Tells whether the channel is transactional. - * @return true if the channel is transactional. - * @throws IOException - */ - boolean isTransactional() throws IOException; - - /** - * Tells the number of unacknowledged messages in this channel. - * @return number of unacknowledged messages. - * @throws IOException - */ - int getUnacknowledgedMessageCount() throws IOException; - - - //********** Operations *****************// - - /** - * Commits the transactions if the channel is transactional. - * @throws IOException - * @throws JMException - */ - void commitTransactions() throws IOException, JMException; - - /** - * Rollsback the transactions if the channel is transactional. - * @throws IOException - * @throws JMException - */ - void rollbackTransactions() throws IOException, JMException; - -} diff --git a/java/broker/src/org/apache/qpid/server/RequiredDeliveryException.java b/java/broker/src/org/apache/qpid/server/RequiredDeliveryException.java deleted file mode 100644 index 87691ccaa3..0000000000 --- a/java/broker/src/org/apache/qpid/server/RequiredDeliveryException.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server; - -import org.apache.qpid.framing.BasicPublishBody; -import org.apache.qpid.framing.ContentHeaderBody; -import org.apache.qpid.framing.ContentBody; -import org.apache.qpid.framing.CompositeAMQDataBlock; -import org.apache.qpid.framing.BasicReturnBody; -import org.apache.qpid.framing.AMQFrame; -import org.apache.qpid.AMQException; -import org.apache.qpid.server.queue.AMQMessage; - -import java.util.List; - -/** - * Signals that a required delivery could not be made. This could be bacuse of - * the immediate flag being set and the queue having no consumers, or the mandatory - * flag being set and the exchange having no valid bindings. - */ -public abstract class RequiredDeliveryException extends AMQException -{ - private final String _message; - private final BasicPublishBody _publishBody; - private final ContentHeaderBody _contentHeaderBody; - private final List _contentBodies; - - public RequiredDeliveryException(String message, AMQMessage payload) - { - super(message); - _message = message; - _publishBody = payload.getPublishBody(); - _contentHeaderBody = payload.getContentHeaderBody(); - _contentBodies = payload.getContentBodies(); - } - - public RequiredDeliveryException(String message, - BasicPublishBody publishBody, - ContentHeaderBody contentHeaderBody, - List contentBodies) - { - super(message); - _message = message; - _publishBody = publishBody; - _contentHeaderBody = contentHeaderBody; - _contentBodies = contentBodies; - } - - public BasicPublishBody getPublishBody() - { - return _publishBody; - } - - public ContentHeaderBody getContentHeaderBody() - { - return _contentHeaderBody; - } - - public List getContentBodies() - { - return _contentBodies; - } - - public CompositeAMQDataBlock getReturnMessage(int channel) - { - BasicReturnBody returnBody = new BasicReturnBody(); - returnBody.exchange = _publishBody.exchange; - returnBody.replyCode = getReplyCode(); - returnBody.replyText = _message; - returnBody.routingKey = _publishBody.routingKey; - - AMQFrame[] allFrames = new AMQFrame[2 + _contentBodies.size()]; - - AMQFrame returnFrame = new AMQFrame(); - returnFrame.bodyFrame = returnBody; - returnFrame.channel = channel; - - allFrames[0] = returnFrame; - allFrames[1] = ContentHeaderBody.createAMQFrame(channel, _contentHeaderBody); - for (int i = 2; i < allFrames.length; i++) - { - allFrames[i] = ContentBody.createAMQFrame(channel, _contentBodies.get(i - 2)); - } - - return new CompositeAMQDataBlock(allFrames); - } - - public int getErrorCode() - { - return getReplyCode(); - } - - public abstract int getReplyCode(); -} diff --git a/java/broker/src/org/apache/qpid/server/ack/TxAck.java b/java/broker/src/org/apache/qpid/server/ack/TxAck.java deleted file mode 100644 index a4cb1f1e71..0000000000 --- a/java/broker/src/org/apache/qpid/server/ack/TxAck.java +++ /dev/null @@ -1,132 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.ack; - -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; -import org.apache.qpid.server.queue.AMQMessage; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.txn.TxnOp; - -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; - -/** - * A TxnOp implementation for handling accumulated acks - */ -public class TxAck implements TxnOp -{ - private final UnacknowledgedMessageMap _map; - private final List _unacked = new LinkedList(); - private final List _individual = new LinkedList(); - private long _deliveryTag; - private boolean _multiple; - - public TxAck(UnacknowledgedMessageMap map) - { - _map = map; - } - - public void update(long deliveryTag, boolean multiple) - { - if(!multiple) - { - //have acked a single message that is not part of - //the previously acked region so record - //individually - _individual.add(deliveryTag);//_multiple && !multiple - } - else if(deliveryTag > _deliveryTag) - { - //have simply moved the last acked message on a - //bit - _deliveryTag = deliveryTag; - _multiple = true; - } - } - - public void consolidate() - { - //lookup all the unacked messages that have been acked in this transaction - if(_multiple) - { - //get all the unacked messages for the accumulated - //multiple acks - _map.collect(_deliveryTag, true, _unacked); - } - //get any unacked messages for individual acks outside the - //range covered by multiple acks - for(long tag : _individual) - { - if(_deliveryTag < tag) - { - _map.collect(tag, false, _unacked); - } - } - } - - public boolean checkPersistent() throws AMQException - { - //if any of the messages in unacked are persistent the txn - //buffer must be marked as persistent: - for(UnacknowledgedMessage msg : _unacked) - { - if(msg.message.isPersistent()) - { - return true; - } - } - return false; - } - - public void prepare() throws AMQException - { - //make persistent changes, i.e. dequeue and decrementReference - for(UnacknowledgedMessage msg : _unacked) - { - msg.discard(); - } - } - - public void undoPrepare() - { - //decrementReference is annoyingly untransactional (due to - //in memory counter) so if we failed in prepare for full - //txn, this op will have to compensate by fixing the count - //in memory (persistent changes will be rolled back by store) - for(UnacknowledgedMessage msg : _unacked) - { - msg.message.incrementReference(); - } - } - - public void commit() - { - //remove the unacked messages from the channels map - _map.remove(_unacked); - } - - public void rollback() - { - } -} - diff --git a/java/broker/src/org/apache/qpid/server/ack/UnacknowledgedMessage.java b/java/broker/src/org/apache/qpid/server/ack/UnacknowledgedMessage.java deleted file mode 100644 index 0eff5a3cca..0000000000 --- a/java/broker/src/org/apache/qpid/server/ack/UnacknowledgedMessage.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.ack; - -import org.apache.qpid.AMQException; -import org.apache.qpid.server.queue.AMQMessage; -import org.apache.qpid.server.queue.AMQQueue; - -public class UnacknowledgedMessage -{ - public final AMQMessage message; - public final String consumerTag; - public final long deliveryTag; - public AMQQueue queue; - - public UnacknowledgedMessage(AMQQueue queue, AMQMessage message, String consumerTag, long deliveryTag) - { - this.queue = queue; - this.message = message; - this.consumerTag = consumerTag; - this.deliveryTag = deliveryTag; - } - - public void discard() throws AMQException - { - if (queue != null) - { - message.dequeue(queue); - } - message.decrementReference(); - } -} - diff --git a/java/broker/src/org/apache/qpid/server/ack/UnacknowledgedMessageMap.java b/java/broker/src/org/apache/qpid/server/ack/UnacknowledgedMessageMap.java deleted file mode 100644 index b0bbe224e3..0000000000 --- a/java/broker/src/org/apache/qpid/server/ack/UnacknowledgedMessageMap.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.ack; - -import java.util.List; - -public interface UnacknowledgedMessageMap -{ - public void collect(long deliveryTag, boolean multiple, List msgs); - public void remove(List msgs); -} - diff --git a/java/broker/src/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java b/java/broker/src/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java deleted file mode 100644 index eda3233e56..0000000000 --- a/java/broker/src/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.ack; - -import java.util.List; -import java.util.Map; - -public class UnacknowledgedMessageMapImpl implements UnacknowledgedMessageMap -{ - private final Object _lock; - private Map _map; - - public UnacknowledgedMessageMapImpl(Object lock, Map map) - { - _lock = lock; - _map = map; - } - - public void collect(long deliveryTag, boolean multiple, List msgs) - { - if (multiple) - { - collect(deliveryTag, msgs); - } - else - { - msgs.add(get(deliveryTag)); - } - - } - - public void remove(List msgs) - { - synchronized(_lock) - { - for(UnacknowledgedMessage msg : msgs) - { - _map.remove(msg.deliveryTag); - } - } - } - - private UnacknowledgedMessage get(long key) - { - synchronized(_lock) - { - return _map.get(key); - } - } - - private void collect(long key, List msgs) - { - synchronized(_lock) - { - for(Map.Entry entry : _map.entrySet()) - { - msgs.add(entry.getValue()); - if (entry.getKey() == key) - { - break; - } - } - } - } -} - diff --git a/java/broker/src/org/apache/qpid/server/configuration/Configurator.java b/java/broker/src/org/apache/qpid/server/configuration/Configurator.java deleted file mode 100644 index 5e3ac03ba7..0000000000 --- a/java/broker/src/org/apache/qpid/server/configuration/Configurator.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.configuration; - -import org.apache.commons.configuration.Configuration; -import org.apache.log4j.Logger; -import org.apache.qpid.configuration.Configured; -import org.apache.qpid.configuration.PropertyUtils; -import org.apache.qpid.configuration.PropertyException; -import org.apache.qpid.server.registry.ApplicationRegistry; - -import java.lang.reflect.Field; - -/** - * This class contains utilities for populating classes automatically from values pulled from configuration - * files. - */ -public class Configurator -{ - private static final Logger _logger = Logger.getLogger(Configurator.class); - - /** - * Configure a given instance using the application configuration. Note that superclasses are not - * currently configured but this could easily be added if required. - * @param instance the instance to configure - */ - public static void configure(Object instance) - { - final Configuration config = ApplicationRegistry.getInstance().getConfiguration(); - - for (Field f : instance.getClass().getDeclaredFields()) - { - Configured annotation = f.getAnnotation(Configured.class); - if (annotation != null) - { - setValueInField(f, instance, config, annotation); - } - } - } - - private static void setValueInField(Field f, Object instance, Configuration config, Configured annotation) - { - Class fieldClass = f.getType(); - String configPath = annotation.path(); - try - { - if (fieldClass == String.class) - { - String val = config.getString(configPath, annotation.defaultValue()); - val = PropertyUtils.replaceProperties(val); - f.set(instance, val); - } - else if (fieldClass == int.class) - { - int val = config.getInt(configPath, Integer.parseInt(annotation.defaultValue())); - f.setInt(instance, val); - } - else if (fieldClass == long.class) - { - long val = config.getLong(configPath, Long.parseLong(annotation.defaultValue())); - f.setLong(instance, val); - } - else if (fieldClass == double.class) - { - double val = config.getDouble(configPath, Double.parseDouble(annotation.defaultValue())); - f.setDouble(instance, val); - } - else if (fieldClass == boolean.class) - { - boolean val = config.getBoolean(configPath, Boolean.parseBoolean(annotation.defaultValue())); - f.setBoolean(instance, val); - } - else - { - _logger.error("Unsupported field type " + fieldClass + " for " + f + " IGNORING configured value"); - } - } - catch (PropertyException e) - { - _logger.error("Unable to expand property: " + e + " INGORING field " + f, e); - } - catch (IllegalAccessException e) - { - _logger.error("Unable to access field " + f + " IGNORING configured value"); - } - } -} \ No newline at end of file diff --git a/java/broker/src/org/apache/qpid/server/configuration/VirtualHostConfiguration.java b/java/broker/src/org/apache/qpid/server/configuration/VirtualHostConfiguration.java deleted file mode 100644 index 9ecbf3d31a..0000000000 --- a/java/broker/src/org/apache/qpid/server/configuration/VirtualHostConfiguration.java +++ /dev/null @@ -1,220 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.configuration; - -import org.apache.qpid.url.AMQBindingURL; -import org.apache.qpid.url.URLSyntaxException; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.queue.QueueRegistry; -import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.server.exchange.ExchangeRegistry; -import org.apache.qpid.server.store.MessageStore; -import org.apache.qpid.AMQException; -import org.apache.log4j.Logger; -import org.apache.commons.configuration.ConfigurationException; -import org.apache.commons.configuration.XMLConfiguration; - - -import java.util.Collection; - -public class VirtualHostConfiguration -{ - private static final Logger _logger = Logger.getLogger(VirtualHostConfiguration.class); - - XMLConfiguration _config; - - private static final String XML_VIRTUALHOST = "virtualhost"; - private static final String XML_PATH = "path"; - private static final String XML_BIND = "bind"; - private static final String XML_VIRTUALHOST_PATH = "virtualhost.path"; - private static final String XML_VIRTUALHOST_BIND = "virtualhost.bind"; - - - public VirtualHostConfiguration(String configFile) throws ConfigurationException - { - _logger.info("Loading Config file:" + configFile); - - _config = new XMLConfiguration(configFile); - - if (_config.getProperty(XML_VIRTUALHOST_PATH) == null) - { - throw new ConfigurationException( - "Virtualhost Configuration document does not contain a valid virtualhost."); - } - } - - public void performBindings() throws AMQException, ConfigurationException, URLSyntaxException - { - Object prop = _config.getProperty(XML_VIRTUALHOST_PATH); - - if (prop instanceof Collection) - { - _logger.debug("Number of VirtualHosts: " + ((Collection) prop).size()); - - int virtualhosts = ((Collection) prop).size(); - for (int vhost = 0; vhost < virtualhosts; vhost++) - { - loadVirtualHost(vhost); - } - } - else - { - loadVirtualHost(-1); - } - } - - private void loadVirtualHost(int index) throws AMQException, ConfigurationException, URLSyntaxException - { - String path = XML_VIRTUALHOST; - - if (index != -1) - { - path = path + "(" + index + ")"; - } - - Object prop = _config.getProperty(path + "." + XML_PATH); - - if (prop == null) - { - prop = _config.getProperty(path + "." + XML_BIND); - String error = "Virtual Host not defined for binding"; - - if (prop != null) - { - if (prop instanceof Collection) - { - error += "s"; - } - - error += ": " + prop; - } - - throw new ConfigurationException(error); - } - - _logger.info("VirtualHost:'" + prop + "'"); - - prop = _config.getProperty(path + "." + XML_BIND); - if (prop instanceof Collection) - { - int bindings = ((Collection) prop).size(); - _logger.debug("Number of Bindings: " + bindings); - for (int dest = 0; dest < bindings; dest++) - { - loadBinding(path, dest); - } - } - else - { - loadBinding(path, -1); - } - } - - private void loadBinding(String rootpath, int index) throws AMQException, ConfigurationException, URLSyntaxException - { - String path = rootpath + "." + XML_BIND; - if (index != -1) - { - path = path + "(" + index + ")"; - } - - String bindingString = _config.getString(path); - - AMQBindingURL binding = new AMQBindingURL(bindingString); - - _logger.debug("Loaded Binding:" + binding); - - try - { - bind(binding); - } - catch (AMQException amqe) - { - _logger.info("Unable to bind url: " + binding); - throw amqe; - } - } - - private void bind(AMQBindingURL binding) throws AMQException, ConfigurationException - { - - String queueName = binding.getQueueName(); - - // This will occur if the URL is a Topic - if (queueName == null) - { - //todo register valid topic - ///queueName = binding.getDestinationName(); - throw new AMQException("Topics cannot be bound. TODO Register valid topic"); - } - - //Get references to Broker Registries - QueueRegistry queueRegistry = ApplicationRegistry.getInstance().getQueueRegistry(); - MessageStore messageStore = ApplicationRegistry.getInstance().getMessageStore(); - ExchangeRegistry exchangeRegistry = ApplicationRegistry.getInstance().getExchangeRegistry(); - - synchronized (queueRegistry) - { - AMQQueue queue = queueRegistry.getQueue(queueName); - - if (queue == null) - { - _logger.info("Queue '" + binding.getQueueName() + "' does not exists. Creating."); - - queue = new AMQQueue(queueName, - Boolean.parseBoolean(binding.getOption(AMQBindingURL.OPTION_DURABLE)), - null /* These queues will have no owner */, - false /* Therefore autodelete makes no sence */, queueRegistry); - - if (queue.isDurable()) - { - messageStore.createQueue(queue); - } - - queueRegistry.registerQueue(queue); - } - else - { - _logger.info("Queue '" + binding.getQueueName() + "' already exists not creating."); - } - - Exchange defaultExchange = exchangeRegistry.getExchange(binding.getExchangeName()); - synchronized (defaultExchange) - { - if (defaultExchange == null) - { - throw new ConfigurationException("Attempt to bind queue to unknown exchange:" + binding); - } - - defaultExchange.registerQueue(queue.getName(), queue, null); - - if (binding.getRoutingKey() == null || binding.getRoutingKey().equals("")) - { - throw new ConfigurationException("Unknown binding not specified on url:" + binding); - } - - queue.bind(binding.getRoutingKey(), defaultExchange); - } - _logger.info("Queue '" + queue.getName() + "' bound to exchange:" + binding.getExchangeName() + " RK:'" + binding.getRoutingKey() + "'"); - } - } -} diff --git a/java/broker/src/org/apache/qpid/server/exchange/AbstractExchange.java b/java/broker/src/org/apache/qpid/server/exchange/AbstractExchange.java deleted file mode 100644 index 69f5e862d6..0000000000 --- a/java/broker/src/org/apache/qpid/server/exchange/AbstractExchange.java +++ /dev/null @@ -1,139 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.exchange; - -import org.apache.qpid.AMQException; -import org.apache.qpid.server.management.AMQManagedObject; -import org.apache.qpid.server.management.Managable; -import org.apache.qpid.server.management.ManagedObject; - -import javax.management.NotCompliantMBeanException; - -public abstract class AbstractExchange implements Exchange, Managable -{ - private String _name; - - protected boolean _durable; - - protected int _ticket; - - protected ExchangeMBean _exchangeMbean; - - /** - * Whether the exchange is automatically deleted once all queues have detached from it - */ - protected boolean _autoDelete; - - /** - * Abstract MBean class. This has some of the methods implemented from - * management intrerface for exchanges. Any implementaion of an - * Exchange MBean should extend this class. - */ - protected abstract class ExchangeMBean extends AMQManagedObject implements ManagedExchange - { - public ExchangeMBean() throws NotCompliantMBeanException - { - super(ManagedExchange.class, ManagedExchange.TYPE); - } - - public String getObjectInstanceName() - { - return _name; - } - - public String getName() - { - return _name; - } - - public Integer getTicketNo() - { - return _ticket; - } - - public boolean isDurable() - { - return _durable; - } - - public boolean isAutoDelete() - { - return _autoDelete; - } - - } // End of MBean class - - public String getName() - { - return _name; - } - - /** - * Concrete exchanges must implement this method in order to create the managed representation. This is - * called during initialisation (template method pattern). - * @return the MBean - */ - protected abstract ExchangeMBean createMBean() throws AMQException; - - public void initialise(String name, boolean durable, int ticket, boolean autoDelete) throws AMQException - { - _name = name; - _durable = durable; - _autoDelete = autoDelete; - _ticket = ticket; - _exchangeMbean = createMBean(); - _exchangeMbean.register(); - } - - public boolean isDurable() - { - return _durable; - } - - public boolean isAutoDelete() - { - return _autoDelete; - } - - public int getTicket() - { - return _ticket; - } - - public void close() throws AMQException - { - if (_exchangeMbean != null) - { - _exchangeMbean.unregister(); - } - } - - public String toString() - { - return getClass().getName() + "[" + getName() +"]"; - } - - public ManagedObject getManagedObject() - { - return _exchangeMbean; - } - -} diff --git a/java/broker/src/org/apache/qpid/server/exchange/DefaultExchangeFactory.java b/java/broker/src/org/apache/qpid/server/exchange/DefaultExchangeFactory.java deleted file mode 100644 index 0c73e0f9f0..0000000000 --- a/java/broker/src/org/apache/qpid/server/exchange/DefaultExchangeFactory.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.exchange; - -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; - -import java.util.HashMap; -import java.util.Map; - -public class DefaultExchangeFactory implements ExchangeFactory -{ - private static final Logger _logger = Logger.getLogger(DefaultExchangeFactory.class); - - private Map> _exchangeClassMap = new HashMap>(); - - public DefaultExchangeFactory() - { - _exchangeClassMap.put("direct", org.apache.qpid.server.exchange.DestNameExchange.class); - _exchangeClassMap.put("topic", org.apache.qpid.server.exchange.DestWildExchange.class); - _exchangeClassMap.put("headers", org.apache.qpid.server.exchange.HeadersExchange.class); - } - - public Exchange createExchange(String exchange, String type, boolean durable, boolean autoDelete, - int ticket) - throws AMQException - { - Class exchClass = _exchangeClassMap.get(type); - if (exchClass == null) - { - throw new AMQException(_logger, "Unknown exchange type: " + type); - } - try - { - Exchange e = exchClass.newInstance(); - e.initialise(exchange, durable, ticket, autoDelete); - return e; - } - catch (InstantiationException e) - { - throw new AMQException(_logger, "Unable to create exchange: " + e, e); - } - catch (IllegalAccessException e) - { - throw new AMQException(_logger, "Unable to create exchange: " + e, e); - } - } -} diff --git a/java/broker/src/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java b/java/broker/src/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java deleted file mode 100644 index eb9d1acb59..0000000000 --- a/java/broker/src/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.exchange; - -import org.apache.qpid.AMQException; -import org.apache.qpid.server.protocol.ExchangeInitialiser; -import org.apache.qpid.server.queue.AMQMessage; -import org.apache.log4j.Logger; - -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; - -public class DefaultExchangeRegistry implements ExchangeRegistry -{ - private static final Logger _log = Logger.getLogger(DefaultExchangeRegistry.class); - - /** - * Maps from exchange name to exchange instance - */ - private ConcurrentMap _exchangeMap = new ConcurrentHashMap(); - - public DefaultExchangeRegistry(ExchangeFactory exchangeFactory) - { - //create 'standard' exchanges: - try - { - new ExchangeInitialiser().initialise(exchangeFactory, this); - } - catch(AMQException e) - { - _log.error("Failed to initialise exchanges: ", e); - } - } - - public void registerExchange(Exchange exchange) - { - _exchangeMap.put(exchange.getName(), exchange); - } - - public void unregisterExchange(String name, boolean inUse) throws AMQException - { - // TODO: check inUse argument - Exchange e = _exchangeMap.remove(name); - if (e != null) - { - e.close(); - } - else - { - throw new AMQException("Unknown exchange " + name); - } - } - - public Exchange getExchange(String name) - { - return _exchangeMap.get(name); - } - - /** - * Routes content through exchanges, delivering it to 1 or more queues. - * @param payload - * @throws AMQException if something goes wrong delivering data - */ - public void routeContent(AMQMessage payload) throws AMQException - { - final String exchange = payload.getPublishBody().exchange; - final Exchange exch = _exchangeMap.get(exchange); - // there is a small window of opportunity for the exchange to be deleted in between - // the JmsPublish being received (where the exchange is validated) and the final - // content body being received (which triggers this method) - if (exch == null) - { - throw new AMQException("Exchange '" + exchange + "' does not exist"); - } - exch.route(payload); - } -} diff --git a/java/broker/src/org/apache/qpid/server/exchange/DestNameExchange.java b/java/broker/src/org/apache/qpid/server/exchange/DestNameExchange.java deleted file mode 100644 index 085d0aad19..0000000000 --- a/java/broker/src/org/apache/qpid/server/exchange/DestNameExchange.java +++ /dev/null @@ -1,223 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.exchange; - -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.BasicPublishBody; -import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.server.management.MBeanDescription; -import org.apache.qpid.server.management.MBeanConstructor; -import org.apache.qpid.server.queue.AMQMessage; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.registry.ApplicationRegistry; - -import javax.management.JMException; -import javax.management.MBeanException; -import javax.management.NotCompliantMBeanException; -import javax.management.openmbean.*; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -public class DestNameExchange extends AbstractExchange -{ - private static final Logger _logger = Logger.getLogger(DestNameExchange.class); - - /** - * Maps from queue name to queue instances - */ - private final Index _index = new Index(); - - /** - * MBean class implementing the management interfaces. - */ - @MBeanDescription("Management Bean for Direct Exchange") - private final class DestNameExchangeMBean extends ExchangeMBean - { - private String[] _bindingItemNames = {"BindingKey", "QueueNames"}; - private String[] _bindingItemDescriptions = {"Binding key", "Queue Names"}; - private String[] _bindingItemIndexNames = {"BindingKey"}; - private OpenType[] _bindingItemTypes = new OpenType[2]; - - private CompositeType _bindingDataType = null; - private TabularType _bindinglistDataType = null; - private TabularDataSupport _bindingList = null; - - @MBeanConstructor("Creates an MBean for AMQ direct exchange") - public DestNameExchangeMBean() throws NotCompliantMBeanException - { - super(); - init(); - } - - /** - * initialises the OpenType objects. - */ - private void init() - { - try - { - _bindingItemTypes[0] = SimpleType.STRING; - //_bindingItemTypes[1] = ArrayType.getArrayType(SimpleType.STRING); - _bindingItemTypes[1] = new ArrayType(1, SimpleType.STRING); - - _bindingDataType = new CompositeType("QueueBinding", - "Binding key and bound Queue names", - _bindingItemNames, - _bindingItemDescriptions, - _bindingItemTypes); - _bindinglistDataType = new TabularType("Bindings", - "List of queue bindings for " + getName() , - _bindingDataType, - _bindingItemIndexNames); - } - catch(OpenDataException ex) - { - //It should never occur. - _logger.error("OpenDataTypes could not be created.", ex); - throw new RuntimeException(ex); - } - } - - public TabularData viewBindings() - throws OpenDataException - { - Map> bindings = _index.getBindingsMap(); - _bindingList = new TabularDataSupport(_bindinglistDataType); - - for (Map.Entry> entry : bindings.entrySet()) - { - String key = entry.getKey(); - List queueList = new ArrayList(); - - List queues = entry.getValue(); - for (AMQQueue q : queues) - { - queueList.add(q.getName()); - } - - Object[] bindingItemValues = {key, queueList.toArray(new String[0])}; - CompositeData bindingData = new CompositeDataSupport(_bindingDataType, - _bindingItemNames, - bindingItemValues); - _bindingList.put(bindingData); - } - - return _bindingList; - } - - public void createBinding(String queueName, String binding) - throws JMException - { - AMQQueue queue = ApplicationRegistry.getInstance().getQueueRegistry().getQueue(queueName); - - if (queue == null) - { - throw new JMException("Queue \"" + queueName + "\" is not registered with the exchange."); - } - - try - { - registerQueue(binding, queue, null); - queue.bind(binding, DestNameExchange.this); - } - catch (AMQException ex) - { - throw new MBeanException(ex); - } - } - - }// End of MBean class - - - protected ExchangeMBean createMBean() throws AMQException - { - try - { - return new DestNameExchangeMBean(); - } - catch (NotCompliantMBeanException ex) - { - _logger.error("Exception occured in creating the DestNameExchenge", ex); - throw new AMQException("Exception occured in creating the DestNameExchenge", ex); - } - } - - public void registerQueue(String routingKey, AMQQueue queue, FieldTable args) throws AMQException - { - assert queue != null; - assert routingKey != null; - if (!_index.add(routingKey, queue)) - { - _logger.debug("Queue " + queue + " is already registered with routing key " + routingKey); - } - else - { - _logger.debug("Binding queue " + queue + " with routing key " + routingKey - + " to exchange " + this); - } - } - - public void deregisterQueue(String routingKey, AMQQueue queue) throws AMQException - { - assert queue != null; - assert routingKey != null; - - if (!_index.remove(routingKey, queue)) - { - throw new AMQException("Queue " + queue + " was not registered with exchange " + this.getName() + - " with routing key " + routingKey + ". No queue was registered with that routing key"); - } - } - - public void route(AMQMessage payload) throws AMQException - { - BasicPublishBody publishBody = payload.getPublishBody(); - - final String routingKey = publishBody.routingKey; - final List queues = _index.get(routingKey); - if (queues == null || queues.isEmpty()) - { - String msg = "Routing key " + routingKey + " is not known to " + this; - if (publishBody.mandatory) - { - throw new NoRouteException(msg, payload); - } - else - { - _logger.warn(msg); - } - } - else - { - if (_logger.isDebugEnabled()) - { - _logger.debug("Publishing message to queue " + queues); - } - - for (AMQQueue q : queues) - { - q.deliver(payload); - } - } - } -} diff --git a/java/broker/src/org/apache/qpid/server/exchange/DestWildExchange.java b/java/broker/src/org/apache/qpid/server/exchange/DestWildExchange.java deleted file mode 100644 index f6abd53076..0000000000 --- a/java/broker/src/org/apache/qpid/server/exchange/DestWildExchange.java +++ /dev/null @@ -1,226 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.exchange; - -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.framing.BasicPublishBody; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.queue.AMQMessage; -import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.management.MBeanDescription; -import org.apache.qpid.server.management.MBeanConstructor; - -import javax.management.openmbean.*; -import javax.management.JMException; -import javax.management.MBeanException; -import javax.management.NotCompliantMBeanException; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.CopyOnWriteArrayList; - -public class DestWildExchange extends AbstractExchange -{ - private static final Logger _logger = Logger.getLogger(DestWildExchange.class); - - private ConcurrentHashMap> _routingKey2queues = new ConcurrentHashMap>(); - - /** - * DestWildExchangeMBean class implements the management interface for the - * Topic exchanges. - */ - @MBeanDescription("Management Bean for Topic Exchange") - private final class DestWildExchangeMBean extends ExchangeMBean - { - private String[] _bindingItemNames = {"BindingKey", "QueueNames"}; - private String[] _bindingItemDescriptions = {"Binding key", "Queue Names"}; - private String[] _bindingItemIndexNames = {"BindingKey"}; - private OpenType[] _bindingItemTypes = new OpenType[2]; - - private CompositeType _bindingDataType = null; - private TabularType _bindinglistDataType = null; - private TabularDataSupport _bindingList = null; - - @MBeanConstructor("Creates an MBean for AMQ topic exchange") - public DestWildExchangeMBean() throws NotCompliantMBeanException - { - super(); - init(); - } - - /** - * initialises the OpenType objects. - */ - private void init() - { - try - { - _bindingItemTypes[0] = SimpleType.STRING; - _bindingItemTypes[1] = new ArrayType(1, SimpleType.STRING); - - _bindingDataType = new CompositeType("QueueBinding", - "Binding key and bound Queue names", - _bindingItemNames, - _bindingItemDescriptions, - _bindingItemTypes); - _bindinglistDataType = new TabularType("Bindings", - "List of queue bindings for " + getName(), - _bindingDataType, - _bindingItemIndexNames); - } - catch(OpenDataException ex) - { - //It should never occur. - _logger.error("OpenDataTypes could not be created.", ex); - throw new RuntimeException(ex); - } - } - - public TabularData viewBindings() - throws OpenDataException - { - _bindingList = new TabularDataSupport(_bindinglistDataType); - - for (Map.Entry> entry : _routingKey2queues.entrySet()) - { - String key = entry.getKey(); - List queueList = new ArrayList(); - - List queues = entry.getValue(); - for (AMQQueue q : queues) - { - queueList.add(q.getName()); - } - - Object[] bindingItemValues = {key, queueList.toArray(new String[0])}; - CompositeData bindingData = new CompositeDataSupport(_bindingDataType, - _bindingItemNames, - bindingItemValues); - _bindingList.put(bindingData); - } - - return _bindingList; - } - - public void createBinding(String queueName, String binding) - throws JMException - { - AMQQueue queue = ApplicationRegistry.getInstance().getQueueRegistry().getQueue(queueName); - - if (queue == null) - throw new JMException("Queue \"" + queueName + "\" is not registered with the exchange."); - - try - { - registerQueue(binding, queue, null); - queue.bind(binding, DestWildExchange.this); - } - catch (AMQException ex) - { - throw new MBeanException(ex); - } - } - - } // End of MBean class - - - public void registerQueue(String routingKey, AMQQueue queue, FieldTable args) throws AMQException - { - assert queue != null; - assert routingKey != null; - // we need to use putIfAbsent, which is an atomic operation, to avoid a race condition - List queueList = _routingKey2queues.putIfAbsent(routingKey, new CopyOnWriteArrayList()); - // if we got null back, no previous value was associated with the specified routing key hence - // we need to read back the new value just put into the map - if (queueList == null) - { - queueList = _routingKey2queues.get(routingKey); - } - if (!queueList.contains(queue)) - { - queueList.add(queue); - } - else if(_logger.isDebugEnabled()) - { - _logger.debug("Queue " + queue + " is already registered with routing key " + routingKey); - } - - } - - public void route(AMQMessage payload) throws AMQException - { - BasicPublishBody publishBody = payload.getPublishBody(); - - final String routingKey = publishBody.routingKey; - List queues = _routingKey2queues.get(routingKey); - // if we have no registered queues we have nothing to do - // TODO: add support for the immediate flag - if (queues == null) - { - //todo Check for valid topic - mritchie - return; - } - - for (AMQQueue q : queues) - { - // TODO: modify code generator to add clone() method then clone the deliver body - // without this addition we have a race condition - we will be modifying the body - // before the encoder has encoded the body for delivery - q.deliver(payload); - } - } - - public void deregisterQueue(String routingKey, AMQQueue queue) throws AMQException - { - assert queue != null; - assert routingKey != null; - - List queues = _routingKey2queues.get(routingKey); - if (queues == null) - { - throw new AMQException("Queue " + queue + " was not registered with exchange " + this.getName() + - " with routing key " + routingKey + ". No queue was registered with that routing key"); - - } - boolean removedQ = queues.remove(queue); - if (!removedQ) - { - throw new AMQException("Queue " + queue + " was not registered with exchange " + this.getName() + - " with routing key " + routingKey); - } - } - - protected ExchangeMBean createMBean() throws AMQException - { - try - { - return new DestWildExchangeMBean(); - } - catch (NotCompliantMBeanException ex) - { - _logger.error("Exception occured in creating the DestWildExchenge", ex); - throw new AMQException("Exception occured in creating the DestWildExchenge", ex); - } - } -} diff --git a/java/broker/src/org/apache/qpid/server/exchange/Exchange.java b/java/broker/src/org/apache/qpid/server/exchange/Exchange.java deleted file mode 100644 index 787d0eddfd..0000000000 --- a/java/broker/src/org/apache/qpid/server/exchange/Exchange.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.exchange; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.queue.AMQMessage; - -public interface Exchange -{ - String getName(); - - void initialise(String name, boolean durable, int ticket, boolean autoDelete) throws AMQException; - - boolean isDurable(); - - /** - * @return true if the exchange will be deleted after all queues have been detached - */ - boolean isAutoDelete(); - - int getTicket(); - - void close() throws AMQException; - - void registerQueue(String routingKey, AMQQueue queue, FieldTable args) throws AMQException; - - void deregisterQueue(String routingKey, AMQQueue queue) throws AMQException; - - void route(AMQMessage message) throws AMQException; -} diff --git a/java/broker/src/org/apache/qpid/server/exchange/ExchangeFactory.java b/java/broker/src/org/apache/qpid/server/exchange/ExchangeFactory.java deleted file mode 100644 index 37ba883bc3..0000000000 --- a/java/broker/src/org/apache/qpid/server/exchange/ExchangeFactory.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.exchange; - -import org.apache.qpid.AMQException; - - -public interface ExchangeFactory -{ - Exchange createExchange(String exchange, String type, boolean durable, boolean autoDelete, - int ticket) - throws AMQException; -} diff --git a/java/broker/src/org/apache/qpid/server/exchange/ExchangeInUseException.java b/java/broker/src/org/apache/qpid/server/exchange/ExchangeInUseException.java deleted file mode 100644 index 6b2891c573..0000000000 --- a/java/broker/src/org/apache/qpid/server/exchange/ExchangeInUseException.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.exchange; - -import org.apache.qpid.AMQException; - -public class ExchangeInUseException extends AMQException -{ - public ExchangeInUseException(String exchangeName) - { - super("Exchange " + exchangeName + " is currently in use"); - } -} diff --git a/java/broker/src/org/apache/qpid/server/exchange/ExchangeRegistry.java b/java/broker/src/org/apache/qpid/server/exchange/ExchangeRegistry.java deleted file mode 100644 index dcc50a796a..0000000000 --- a/java/broker/src/org/apache/qpid/server/exchange/ExchangeRegistry.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.exchange; - -import org.apache.qpid.AMQException; -import org.apache.qpid.server.queue.AMQMessage; - - -public interface ExchangeRegistry extends MessageRouter -{ - void registerExchange(Exchange exchange); - - /** - * Unregister an exchange - * @param name name of the exchange to delete - * @param inUse if true, do NOT delete the exchange if it is in use (has queues bound to it) - * @throws ExchangeInUseException when the exchange cannot be deleted because it is in use - * @throws AMQException - */ - void unregisterExchange(String name, boolean inUse) throws ExchangeInUseException, AMQException; - - Exchange getExchange(String name); -} diff --git a/java/broker/src/org/apache/qpid/server/exchange/HeadersBinding.java b/java/broker/src/org/apache/qpid/server/exchange/HeadersBinding.java deleted file mode 100644 index b058211288..0000000000 --- a/java/broker/src/org/apache/qpid/server/exchange/HeadersBinding.java +++ /dev/null @@ -1,145 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.exchange; - -import org.apache.log4j.Logger; - -import java.util.Collections; -import java.util.Map; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Set; - -/** - * Defines binding and matching based on a set of headers. - */ -class HeadersBinding -{ - private static final Logger _logger = Logger.getLogger(HeadersBinding.class); - - private final Map _mappings = new HashMap(); - private final Set required = new HashSet(); - private final Set matches = new HashSet(); - private boolean matchAny; - - /** - * Creates a binding for a set of mappings. Those mappings whose value is - * null or the empty string are assumed only to be required headers, with - * no constraint on the value. Those with a non-null value are assumed to - * define a required match of value. - * @param mappings the defined mappings this binding should use - */ - HeadersBinding(Map mappings) - { - //noinspection unchecked - this(mappings == null ? new HashSet() : mappings.entrySet()); - _mappings.putAll(mappings); - } - - private HeadersBinding(Set entries) - { - for (Map.Entry e : entries) - { - if (isSpecial(e.getKey())) - { - processSpecial((String) e.getKey(), e.getValue()); - } - else if (e.getValue() == null || e.getValue().equals("")) - { - required.add(e.getKey()); - } - else - { - matches.add(e); - } - } - } - - protected Map getMappings() - { - return _mappings; - } - - /** - * Checks whether the supplied headers match the requirements of this binding - * @param headers the headers to check - * @return true if the headers define any required keys and match any required - * values - */ - public boolean matches(Map headers) - { - if(headers == null) - { - return required.isEmpty() && matches.isEmpty(); - } - else - { - return matchAny ? or(headers) : and(headers); - } - } - - private boolean and(Map headers) - { - //need to match all the defined mapping rules: - return headers.keySet().containsAll(required) - && headers.entrySet().containsAll(matches); - } - - private boolean or(Map headers) - { - //only need to match one mapping rule: - return !Collections.disjoint(headers.keySet(), required) - || !Collections.disjoint(headers.entrySet(), matches); - } - - private void processSpecial(String key, Object value) - { - if("X-match".equalsIgnoreCase(key)) - { - matchAny = isAny(value); - } - else - { - _logger.warn("Ignoring special header: " + key); - } - } - - private boolean isAny(Object value) - { - if(value instanceof String) - { - if("any".equalsIgnoreCase((String) value)) return true; - if("all".equalsIgnoreCase((String) value)) return false; - } - _logger.warn("Ignoring unrecognised match type: " + value); - return false;//default to all - } - - static boolean isSpecial(Object key) - { - return key instanceof String && isSpecial((String) key); - } - - static boolean isSpecial(String key) - { - return key.startsWith("X-") || key.startsWith("x-"); - } -} diff --git a/java/broker/src/org/apache/qpid/server/exchange/HeadersExchange.java b/java/broker/src/org/apache/qpid/server/exchange/HeadersExchange.java deleted file mode 100644 index 961d4ddf4c..0000000000 --- a/java/broker/src/org/apache/qpid/server/exchange/HeadersExchange.java +++ /dev/null @@ -1,271 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.exchange; - -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.BasicContentHeaderProperties; -import org.apache.qpid.framing.ContentHeaderBody; -import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.server.management.MBeanConstructor; -import org.apache.qpid.server.management.MBeanDescription; -import org.apache.qpid.server.queue.AMQMessage; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.registry.ApplicationRegistry; - -import javax.management.JMException; -import javax.management.NotCompliantMBeanException; -import javax.management.openmbean.*; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.concurrent.CopyOnWriteArrayList; - -/** - * An exchange that binds queues based on a set of required headers and header values - * and routes messages to these queues by matching the headers of the message against - * those with which the queues were bound. - *

    - *

    - * The Headers Exchange
    - *
    - *  Routes messages according to the value/presence of fields in the message header table.
    - *  (Basic and JMS content has a content header field called "headers" that is a table of
    - *   message header fields).
    - *
    - *  class = "headers"
    - *  routing key is not used
    - *
    - *  Has the following binding arguments:
    - *
    - *  the X-match field - if "all", does an AND match (used for GRM), if "any", does an OR match.
    - *  other fields prefixed with "X-" are ignored (and generate a console warning message).
    - *  a field with no value or empty value indicates a match on presence only.
    - *  a field with a value indicates match on field presence and specific value.
    - *
    - *  Standard instances:
    - *
    - *  amq.match - pub/sub on field content/value
    - *  
    - */ -public class HeadersExchange extends AbstractExchange -{ - private static final Logger _logger = Logger.getLogger(HeadersExchange.class); - - private final List _bindings = new CopyOnWriteArrayList(); - - /** - * HeadersExchangeMBean class implements the management interface for the - * Header Exchanges. - */ - @MBeanDescription("Management Bean for Headers Exchange") - private final class HeadersExchangeMBean extends ExchangeMBean - { - private String[] _bindingItemNames = {"Queue", "HeaderBinding"}; - private String[] _bindingItemDescriptions = {"Queue Name", "Header attribute bindings"}; - private String[] _bindingItemIndexNames = {"HeaderBinding"}; - private OpenType[] _bindingItemTypes = new OpenType[2]; - - private CompositeType _bindingDataType = null; - private TabularType _bindinglistDataType = null; - private TabularDataSupport _bindingList = null; - - @MBeanConstructor("Creates an MBean for AMQ Headers exchange") - public HeadersExchangeMBean() throws NotCompliantMBeanException - { - super(); - init(); - } - /** - * initialises the OpenType objects. - */ - private void init() - { - try - { - _bindingItemTypes[0] = SimpleType.STRING; - _bindingItemTypes[1] = new ArrayType(1, SimpleType.STRING); - - _bindingDataType = new CompositeType("QueueAndHeaderAttributesBinding", - "Queue name and header bindings", - _bindingItemNames, - _bindingItemDescriptions, - _bindingItemTypes); - _bindinglistDataType = new TabularType("HeaderBindings", - "List of queue bindings for " + getName(), - _bindingDataType, - _bindingItemIndexNames); - } - catch(OpenDataException ex) - { - //It should never occur. - _logger.error("OpenDataTypes could not be created.", ex); - throw new RuntimeException(ex); - } - } - - public TabularData viewBindings() - throws OpenDataException - { - _bindingList = new TabularDataSupport(_bindinglistDataType); - for (Iterator itr = _bindings.iterator(); itr.hasNext();) - { - Registration registration = itr.next(); - String queueName = registration.queue.getName(); - - HeadersBinding headers = registration.binding; - Map headerMappings = headers.getMappings(); - List mappingList = new ArrayList(); - - for (Map.Entry en : headerMappings.entrySet()) - { - String key = en.getKey().toString(); - String value = en.getValue().toString(); - - mappingList.add(key + "=" + value); - } - - Object[] bindingItemValues = {queueName, mappingList.toArray(new String[0])}; - CompositeData bindingData = new CompositeDataSupport(_bindingDataType, - _bindingItemNames, - bindingItemValues); - _bindingList.put(bindingData); - } - - return _bindingList; - } - - /** - * Creates bindings. Binding pattern is as follows- - * =,=,... - * @param queueName - * @param binding - * @throws JMException - */ - public void createBinding(String queueName, String binding) - throws JMException - { - AMQQueue queue = ApplicationRegistry.getInstance().getQueueRegistry().getQueue(queueName); - - if (queue == null) - { - throw new JMException("Queue \"" + queueName + "\" is not registered with the exchange."); - } - - String[] bindings = binding.split(","); - FieldTable fieldTable = new FieldTable(); - for (int i = 0; i < bindings.length; i++) - { - String[] keyAndValue = bindings[i].split("="); - if (keyAndValue == null || keyAndValue.length < 2) - { - throw new JMException("Format for headers binding should be \"=,=\" "); - } - fieldTable.put(keyAndValue[0], keyAndValue[1]); - } - - _bindings.add(new Registration(new HeadersBinding(fieldTable), queue)); - } - - } // End of MBean class - - public void registerQueue(String routingKey, AMQQueue queue, FieldTable args) throws AMQException - { - _logger.debug("Exchange " + getName() + ": Binding " + queue.getName() + " with " + args); - _bindings.add(new Registration(new HeadersBinding(args), queue)); - } - - public void deregisterQueue(String routingKey, AMQQueue queue) throws AMQException - { - _logger.debug("Exchange " + getName() + ": Unbinding " + queue.getName()); - _bindings.remove(new Registration(null, queue)); - } - - public void route(AMQMessage payload) throws AMQException - { - Map headers = getHeaders(payload.getContentHeaderBody()); - if (_logger.isDebugEnabled()) - { - _logger.debug("Exchange " + getName() + ": routing message with headers " + headers); - } - boolean delivered = false; - for (Registration e : _bindings) - { - if (e.binding.matches(headers)) - { - if (_logger.isDebugEnabled()) - { - _logger.debug("Exchange " + getName() + ": delivering message with headers " + - headers + " to " + e.queue.getName()); - } - e.queue.deliver(payload); - delivered = true; - } - } - if (!delivered) - { - _logger.warn("Exchange " + getName() + ": message not routable."); - } - } - - protected Map getHeaders(ContentHeaderBody contentHeaderFrame) - { - //what if the content type is not 'basic'? 'file' and 'stream' content classes also define headers, - //but these are not yet implemented. - return ((BasicContentHeaderProperties) contentHeaderFrame.properties).getHeaders(); - } - - protected ExchangeMBean createMBean() throws AMQException - { - try - { - return new HeadersExchangeMBean(); - } - catch (NotCompliantMBeanException ex) - { - _logger.error("Exception occured in creating the HeadersExchangeMBean", ex); - throw new AMQException("Exception occured in creating the HeadersExchangeMBean", ex); - } - } - - private static class Registration - { - private final HeadersBinding binding; - private final AMQQueue queue; - - Registration(HeadersBinding binding, AMQQueue queue) - { - this.binding = binding; - this.queue = queue; - } - - public int hashCode() - { - return queue.hashCode(); - } - - public boolean equals(Object o) - { - return o instanceof Registration && ((Registration) o).queue.equals(queue); - } - } -} diff --git a/java/broker/src/org/apache/qpid/server/exchange/Index.java b/java/broker/src/org/apache/qpid/server/exchange/Index.java deleted file mode 100644 index fb48729c9e..0000000000 --- a/java/broker/src/org/apache/qpid/server/exchange/Index.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.exchange; - -import org.apache.qpid.server.queue.AMQQueue; - -import java.util.List; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.CopyOnWriteArrayList; - -/** - * An index of queues against routing key. Allows multiple queues to be stored - * against the same key. Used in the DestNameExchange. - */ -class Index -{ - private ConcurrentMap> _index - = new ConcurrentHashMap>(); - - boolean add(String key, AMQQueue queue) - { - List queues = _index.get(key); - if(queues == null) - { - queues = new CopyOnWriteArrayList(); - //next call is atomic, so there is no race to create the list - List active = _index.putIfAbsent(key, queues); - if(active != null) - { - //someone added the new one in faster than we did, so use theirs - queues = active; - } - } - if(queues.contains(queue)) - { - return false; - } - else - { - return queues.add(queue); - } - } - - boolean remove(String key, AMQQueue queue) - { - List queues = _index.get(key); - if (queues != null) - { - boolean removed = queues.remove(queue); - if (queues.size() == 0) - { - _index.remove(key); - } - return removed; - } - return false; - } - - List get(String key) - { - return _index.get(key); - } - - Map> getBindingsMap() - { - return _index; - } -} diff --git a/java/broker/src/org/apache/qpid/server/exchange/ManagedExchange.java b/java/broker/src/org/apache/qpid/server/exchange/ManagedExchange.java deleted file mode 100644 index 3c2c105186..0000000000 --- a/java/broker/src/org/apache/qpid/server/exchange/ManagedExchange.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.exchange; - -import org.apache.qpid.server.management.MBeanAttribute; -import org.apache.qpid.server.management.MBeanOperation; -import org.apache.qpid.server.management.MBeanOperationParameter; - -import javax.management.openmbean.TabularData; -import javax.management.JMException; -import javax.management.MBeanOperationInfo; -import java.io.IOException; - -/** - * The management interface exposed to allow management of an Exchange. - * @author Robert J. Greig - * @author Bhupendra Bhardwaj - * @version 0.1 - */ -public interface ManagedExchange -{ - static final String TYPE = "Exchange"; - - /** - * Returns the name of the managed exchange. - * @return the name of the exchange. - * @throws IOException - */ - @MBeanAttribute(name="Name", description="Name of exchange") - String getName() throws IOException; - - @MBeanAttribute(name="TicketNo", description="Exchange Ticket No") - Integer getTicketNo() throws IOException; - - /** - * Tells if the exchange is durable or not. - * @return true if the exchange is durable. - * @throws IOException - */ - @MBeanAttribute(name="Durable", description="true if Exchange is durable") - boolean isDurable() throws IOException; - - /** - * Tells if the exchange is set for autodelete or not. - * @return true if the exchange is set as autodelete. - * @throws IOException - */ - @MBeanAttribute(name="AutoDelete", description="true if Exchange is AutoDelete") - boolean isAutoDelete() throws IOException; - - // Operations - - /** - * Returns all the bindings this exchange has with the queues. - * @return the bindings with the exchange. - * @throws IOException - * @throws JMException - */ - @MBeanOperation(name="viewBindings", description="view the queue bindings for this exchange") - TabularData viewBindings() throws IOException, JMException; - - /** - * Creates new binding with the given queue and binding. - * @param queueName - * @param binding - * @throws JMException - */ - @MBeanOperation(name="createBinding", - description="create a new binding with this exchange", - impact= MBeanOperationInfo.ACTION) - void createBinding(@MBeanOperationParameter(name="queue name", description="queue name") String queueName, - @MBeanOperationParameter(name="binding", description="queue binding")String binding) - throws JMException; - -} \ No newline at end of file diff --git a/java/broker/src/org/apache/qpid/server/exchange/MessageRouter.java b/java/broker/src/org/apache/qpid/server/exchange/MessageRouter.java deleted file mode 100644 index 70b80f65da..0000000000 --- a/java/broker/src/org/apache/qpid/server/exchange/MessageRouter.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.exchange; - -import org.apache.qpid.server.queue.AMQMessage; -import org.apache.qpid.AMQException; - -/** - * Separated out from the ExchangeRegistry interface to allow components - * that use only this part to have a dependency with a reduced footprint. - * - */ -public interface MessageRouter -{ - /** - * Routes content through exchanges, delivering it to 1 or more queues. - * @param message the message to be routed - * @throws org.apache.qpid.AMQException if something goes wrong delivering data - */ - void routeContent(AMQMessage message) throws AMQException; -} diff --git a/java/broker/src/org/apache/qpid/server/exchange/NoRouteException.java b/java/broker/src/org/apache/qpid/server/exchange/NoRouteException.java deleted file mode 100644 index fb0a330263..0000000000 --- a/java/broker/src/org/apache/qpid/server/exchange/NoRouteException.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.exchange; - -import org.apache.qpid.server.RequiredDeliveryException; -import org.apache.qpid.server.queue.AMQMessage; -import org.apache.qpid.protocol.AMQConstant; - -/** - * Thrown by an exchange if there is no way to route a message with the - * mandatory flag set. - */ -public class NoRouteException extends RequiredDeliveryException -{ - public NoRouteException(String msg, AMQMessage message) - { - super(msg, message); - } - - public int getReplyCode() - { - return AMQConstant.NO_ROUTE.getCode(); - } -} diff --git a/java/broker/src/org/apache/qpid/server/handler/BasicAckMethodHandler.java b/java/broker/src/org/apache/qpid/server/handler/BasicAckMethodHandler.java deleted file mode 100644 index b2b7a21296..0000000000 --- a/java/broker/src/org/apache/qpid/server/handler/BasicAckMethodHandler.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.handler; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.BasicAckBody; -import org.apache.qpid.server.exchange.ExchangeRegistry; -import org.apache.qpid.server.protocol.AMQMethodEvent; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.queue.QueueRegistry; -import org.apache.qpid.server.state.AMQStateManager; -import org.apache.qpid.server.state.StateAwareMethodListener; -import org.apache.qpid.server.AMQChannel; - -public class BasicAckMethodHandler implements StateAwareMethodListener -{ - private static final BasicAckMethodHandler _instance = new BasicAckMethodHandler(); - - public static BasicAckMethodHandler getInstance() - { - return _instance; - } - - private BasicAckMethodHandler() - { - } - - public void methodReceived(AMQStateManager stateManager, QueueRegistry queueRegistry, - ExchangeRegistry exchangeRegistry, AMQProtocolSession protocolSession, - AMQMethodEvent evt) throws AMQException - { - BasicAckBody body = evt.getMethod(); - final AMQChannel channel = protocolSession.getChannel(evt.getChannelId()); - // this method throws an AMQException if the delivery tag is not known - channel.acknowledgeMessage(body.deliveryTag, body.multiple); - } -} diff --git a/java/broker/src/org/apache/qpid/server/handler/BasicCancelMethodHandler.java b/java/broker/src/org/apache/qpid/server/handler/BasicCancelMethodHandler.java deleted file mode 100644 index 673556cbec..0000000000 --- a/java/broker/src/org/apache/qpid/server/handler/BasicCancelMethodHandler.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.handler; - -import org.apache.qpid.framing.AMQFrame; -import org.apache.qpid.framing.BasicCancelBody; -import org.apache.qpid.framing.BasicCancelOkBody; -import org.apache.qpid.server.state.StateAwareMethodListener; -import org.apache.qpid.server.state.AMQStateManager; -import org.apache.qpid.server.queue.QueueRegistry; -import org.apache.qpid.server.exchange.ExchangeRegistry; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.protocol.AMQMethodEvent; -import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.AMQException; - -public class BasicCancelMethodHandler implements StateAwareMethodListener -{ - private static final BasicCancelMethodHandler _instance = new BasicCancelMethodHandler(); - - public static BasicCancelMethodHandler getInstance() - { - return _instance; - } - - private BasicCancelMethodHandler() - { - } - - public void methodReceived(AMQStateManager stateManager, QueueRegistry queueRegistry, - ExchangeRegistry exchangeRegistry, AMQProtocolSession protocolSession, - AMQMethodEvent evt) throws AMQException - { - final AMQChannel channel = protocolSession.getChannel(evt.getChannelId()); - final BasicCancelBody body = evt.getMethod(); - channel.unsubscribeConsumer(protocolSession, body.consumerTag); - if(!body.nowait) - { - final AMQFrame responseFrame = BasicCancelOkBody.createAMQFrame(evt.getChannelId(), body.consumerTag); - protocolSession.writeFrame(responseFrame); - } - } -} diff --git a/java/broker/src/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java b/java/broker/src/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java deleted file mode 100644 index d4c94061a0..0000000000 --- a/java/broker/src/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.handler; - -import org.apache.qpid.AMQException; -import org.apache.qpid.protocol.AMQConstant; -import org.apache.qpid.framing.BasicConsumeBody; -import org.apache.qpid.framing.BasicConsumeOkBody; -import org.apache.qpid.framing.ConnectionCloseBody; -import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.server.ConsumerTagNotUniqueException; -import org.apache.qpid.server.exchange.ExchangeRegistry; -import org.apache.qpid.server.protocol.AMQMethodEvent; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.queue.QueueRegistry; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.state.AMQStateManager; -import org.apache.qpid.server.state.StateAwareMethodListener; -import org.apache.log4j.Logger; - -public class BasicConsumeMethodHandler implements StateAwareMethodListener -{ - private static final Logger _log = Logger.getLogger(BasicConsumeMethodHandler.class); - - private static final BasicConsumeMethodHandler _instance = new BasicConsumeMethodHandler(); - - public static BasicConsumeMethodHandler getInstance() - { - return _instance; - } - - private BasicConsumeMethodHandler() - { - } - - public void methodReceived(AMQStateManager stateManager, QueueRegistry queueRegistry, - ExchangeRegistry exchangeRegistry, AMQProtocolSession session, - AMQMethodEvent evt) throws AMQException - { - BasicConsumeBody body = evt.getMethod(); - final int channelId = evt.getChannelId(); - - AMQChannel channel = session.getChannel(channelId); - if (channel == null) - { - _log.error("Channel " + channelId + " not found"); - // TODO: either alert or error that the - } - else - { - AMQQueue queue = body.queue == null ? channel.getDefaultQueue() : queueRegistry.getQueue(body.queue); - - if(queue == null) - { - _log.info("No queue for '" + body.queue + "'"); - } - try - { - String consumerTag = channel.subscribeToQueue(body.consumerTag, queue, session, !body.noAck); - if(!body.nowait) - { - session.writeFrame(BasicConsumeOkBody.createAMQFrame(channelId, consumerTag)); - } - - //now allow queue to start async processing of any backlog of messages - queue.deliverAsync(); - } - catch(ConsumerTagNotUniqueException e) - { - String msg = "Non-unique consumer tag, '" + body.consumerTag + "'"; - session.writeFrame(ConnectionCloseBody.createAMQFrame(channelId, AMQConstant.NOT_ALLOWED.getCode(), msg, BasicConsumeBody.CLASS_ID, BasicConsumeBody.METHOD_ID)); - } - } - } -} diff --git a/java/broker/src/org/apache/qpid/server/handler/BasicPublishMethodHandler.java b/java/broker/src/org/apache/qpid/server/handler/BasicPublishMethodHandler.java deleted file mode 100644 index efdbe7aae4..0000000000 --- a/java/broker/src/org/apache/qpid/server/handler/BasicPublishMethodHandler.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.handler; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQFrame; -import org.apache.qpid.framing.BasicPublishBody; -import org.apache.qpid.framing.ChannelCloseBody; -import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.server.exchange.ExchangeRegistry; -import org.apache.qpid.server.protocol.AMQMethodEvent; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.queue.QueueRegistry; -import org.apache.qpid.server.state.AMQStateManager; -import org.apache.qpid.server.state.StateAwareMethodListener; - -public class BasicPublishMethodHandler implements StateAwareMethodListener -{ - private static final BasicPublishMethodHandler _instance = new BasicPublishMethodHandler(); - - public static BasicPublishMethodHandler getInstance() - { - return _instance; - } - - private BasicPublishMethodHandler() - { - } - - public void methodReceived(AMQStateManager stateManager, QueueRegistry queueRegistry, - ExchangeRegistry exchangeRegistry, AMQProtocolSession protocolSession, - AMQMethodEvent evt) throws AMQException - { - final BasicPublishBody body = evt.getMethod(); - - // TODO: check the delivery tag field details - is it unique across the broker or per subscriber? - if (body.exchange == null) - { - body.exchange = "amq.direct"; - } - Exchange e = exchangeRegistry.getExchange(body.exchange); - // if the exchange does not exist we raise a channel exception - if (e == null) - { - protocolSession.closeChannel(evt.getChannelId()); - // TODO: modify code gen to make getClazz and getMethod public methods rather than protected - // then we can remove the hardcoded 0,0 - AMQFrame cf = ChannelCloseBody.createAMQFrame(evt.getChannelId(), 500, "Unknown exchange name", 0, 0); - protocolSession.writeFrame(cf); - } - else - { - // The partially populated BasicDeliver frame plus the received route body - // is stored in the channel. Once the final body frame has been received - // it is routed to the exchange. - AMQChannel channel = protocolSession.getChannel(evt.getChannelId()); - channel.setPublishFrame(body, protocolSession); - } - } -} - diff --git a/java/broker/src/org/apache/qpid/server/handler/BasicQosHandler.java b/java/broker/src/org/apache/qpid/server/handler/BasicQosHandler.java deleted file mode 100644 index 1357ff16b9..0000000000 --- a/java/broker/src/org/apache/qpid/server/handler/BasicQosHandler.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.handler; - -import org.apache.qpid.framing.AMQFrame; -import org.apache.qpid.framing.BasicQosBody; -import org.apache.qpid.framing.BasicQosOkBody; -import org.apache.qpid.server.state.StateAwareMethodListener; -import org.apache.qpid.server.state.AMQStateManager; -import org.apache.qpid.server.queue.QueueRegistry; -import org.apache.qpid.server.exchange.ExchangeRegistry; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.protocol.AMQMethodEvent; -import org.apache.qpid.AMQException; - -public class BasicQosHandler implements StateAwareMethodListener -{ - private static final BasicQosHandler _instance = new BasicQosHandler(); - - public static BasicQosHandler getInstance() - { - return _instance; - } - - public void methodReceived(AMQStateManager stateMgr, QueueRegistry queues, ExchangeRegistry exchanges, - AMQProtocolSession session, AMQMethodEvent evt) throws AMQException - { - session.getChannel(evt.getChannelId()).setPrefetchCount(evt.getMethod().prefetchCount); - session.writeFrame(new AMQFrame(evt.getChannelId(), new BasicQosOkBody())); - } -} diff --git a/java/broker/src/org/apache/qpid/server/handler/BasicRecoverMethodHandler.java b/java/broker/src/org/apache/qpid/server/handler/BasicRecoverMethodHandler.java deleted file mode 100644 index 85e802d10d..0000000000 --- a/java/broker/src/org/apache/qpid/server/handler/BasicRecoverMethodHandler.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.handler; - -import org.apache.qpid.server.state.StateAwareMethodListener; -import org.apache.qpid.server.state.AMQStateManager; -import org.apache.qpid.server.queue.QueueRegistry; -import org.apache.qpid.server.exchange.ExchangeRegistry; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.protocol.AMQMethodEvent; -import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.framing.BasicRecoverBody; -import org.apache.qpid.AMQException; -import org.apache.log4j.Logger; - -public class BasicRecoverMethodHandler implements StateAwareMethodListener -{ - private static final Logger _logger = Logger.getLogger(BasicRecoverMethodHandler.class); - - private static final BasicRecoverMethodHandler _instance = new BasicRecoverMethodHandler(); - - public static BasicRecoverMethodHandler getInstance() - { - return _instance; - } - - public void methodReceived(AMQStateManager stateManager, QueueRegistry queueRegistry, - ExchangeRegistry exchangeRegistry, AMQProtocolSession protocolSession, - AMQMethodEvent evt) throws AMQException - { - _logger.debug("Recover received on protocol session " + protocolSession + " and channel " + evt.getChannelId()); - AMQChannel channel = protocolSession.getChannel(evt.getChannelId()); - if (channel == null) - { - throw new AMQException("Unknown channel " + evt.getChannelId()); - } - channel.resend(protocolSession); - } -} diff --git a/java/broker/src/org/apache/qpid/server/handler/ChannelCloseHandler.java b/java/broker/src/org/apache/qpid/server/handler/ChannelCloseHandler.java deleted file mode 100644 index 0efe12b137..0000000000 --- a/java/broker/src/org/apache/qpid/server/handler/ChannelCloseHandler.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.handler; - -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.ChannelCloseBody; -import org.apache.qpid.framing.AMQFrame; -import org.apache.qpid.framing.ChannelCloseOkBody; -import org.apache.qpid.server.exchange.ExchangeRegistry; -import org.apache.qpid.server.protocol.AMQMethodEvent; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.queue.QueueRegistry; -import org.apache.qpid.server.state.AMQStateManager; -import org.apache.qpid.server.state.StateAwareMethodListener; - -public class ChannelCloseHandler implements StateAwareMethodListener -{ - private static final Logger _logger = Logger.getLogger(ChannelCloseHandler.class); - - private static ChannelCloseHandler _instance = new ChannelCloseHandler(); - - public static ChannelCloseHandler getInstance() - { - return _instance; - } - - private ChannelCloseHandler() - { - } - - public void methodReceived(AMQStateManager stateManager, QueueRegistry queueRegistry, - ExchangeRegistry exchangeRegistry, AMQProtocolSession protocolSession, - AMQMethodEvent evt) throws AMQException - { - ChannelCloseBody body = evt.getMethod(); - _logger.info("Received channel close for id " + evt.getChannelId() + " citing class " + body.classId + - " and method " + body.methodId); - protocolSession.closeChannel(evt.getChannelId()); - AMQFrame response = ChannelCloseOkBody.createAMQFrame(evt.getChannelId()); - protocolSession.writeFrame(response); - } -} diff --git a/java/broker/src/org/apache/qpid/server/handler/ChannelCloseOkHandler.java b/java/broker/src/org/apache/qpid/server/handler/ChannelCloseOkHandler.java deleted file mode 100644 index fd6714de3a..0000000000 --- a/java/broker/src/org/apache/qpid/server/handler/ChannelCloseOkHandler.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.handler; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.ChannelCloseOkBody; -import org.apache.qpid.server.exchange.ExchangeRegistry; -import org.apache.qpid.server.protocol.AMQMethodEvent; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.queue.QueueRegistry; -import org.apache.qpid.server.state.AMQStateManager; -import org.apache.qpid.server.state.StateAwareMethodListener; -import org.apache.log4j.Logger; - -public class ChannelCloseOkHandler implements StateAwareMethodListener -{ - private static final Logger _logger = Logger.getLogger(ChannelCloseOkHandler.class); - - private static ChannelCloseOkHandler _instance = new ChannelCloseOkHandler(); - - public static ChannelCloseOkHandler getInstance() - { - return _instance; - } - - private ChannelCloseOkHandler() - { - } - - public void methodReceived(AMQStateManager stateManager, QueueRegistry queueRegistry, - ExchangeRegistry exchangeRegistry, AMQProtocolSession protocolSession, - AMQMethodEvent evt) throws AMQException - { - _logger.info("Received channel-close-ok for channel-id " + evt.getChannelId()); - } -} diff --git a/java/broker/src/org/apache/qpid/server/handler/ChannelFlowHandler.java b/java/broker/src/org/apache/qpid/server/handler/ChannelFlowHandler.java deleted file mode 100644 index 8417ada15f..0000000000 --- a/java/broker/src/org/apache/qpid/server/handler/ChannelFlowHandler.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.handler; - -import org.apache.log4j.Logger; -import org.apache.qpid.server.state.AMQStateManager; -import org.apache.qpid.server.state.StateAwareMethodListener; -import org.apache.qpid.server.queue.QueueRegistry; -import org.apache.qpid.server.exchange.ExchangeRegistry; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.protocol.AMQMethodEvent; -import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.framing.AMQFrame; -import org.apache.qpid.framing.ChannelFlowBody; -import org.apache.qpid.framing.ChannelFlowOkBody; -import org.apache.qpid.framing.ChannelCloseBody; -import org.apache.qpid.AMQException; - -public class ChannelFlowHandler implements StateAwareMethodListener -{ - private static final Logger _logger = Logger.getLogger(ChannelFlowHandler.class); - - private static ChannelFlowHandler _instance = new ChannelFlowHandler(); - - public static ChannelFlowHandler getInstance() - { - return _instance; - } - - private ChannelFlowHandler() - { - } - - public void methodReceived(AMQStateManager stateManager, QueueRegistry queueRegistry, - ExchangeRegistry exchangeRegistry, AMQProtocolSession protocolSession, - AMQMethodEvent evt) throws AMQException - { - ChannelFlowBody body = evt.getMethod(); - - AMQChannel channel = protocolSession.getChannel(evt.getChannelId()); - channel.setSuspended(!body.active); - _logger.debug("Channel.Flow for channel " + evt.getChannelId() + ", active=" + body.active); - - AMQFrame response = ChannelFlowOkBody.createAMQFrame(evt.getChannelId(), body.active); - protocolSession.writeFrame(response); - }} diff --git a/java/broker/src/org/apache/qpid/server/handler/ChannelOpenHandler.java b/java/broker/src/org/apache/qpid/server/handler/ChannelOpenHandler.java deleted file mode 100644 index 4cccc774ba..0000000000 --- a/java/broker/src/org/apache/qpid/server/handler/ChannelOpenHandler.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.handler; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQFrame; -import org.apache.qpid.framing.ChannelOpenBody; -import org.apache.qpid.framing.ChannelOpenOkBody; -import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.registry.IApplicationRegistry; -import org.apache.qpid.server.exchange.ExchangeRegistry; -import org.apache.qpid.server.protocol.AMQMethodEvent; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.queue.QueueRegistry; -import org.apache.qpid.server.state.AMQStateManager; -import org.apache.qpid.server.state.StateAwareMethodListener; - -public class ChannelOpenHandler implements StateAwareMethodListener -{ - private static ChannelOpenHandler _instance = new ChannelOpenHandler(); - - public static ChannelOpenHandler getInstance() - { - return _instance; - } - - private ChannelOpenHandler() - { - } - - public void methodReceived(AMQStateManager stateManager, QueueRegistry queueRegistry, - ExchangeRegistry exchangeRegistry, AMQProtocolSession protocolSession, - AMQMethodEvent evt) throws AMQException - { - IApplicationRegistry registry = ApplicationRegistry.getInstance(); - final AMQChannel channel = new AMQChannel(evt.getChannelId(), registry.getMessageStore(), - exchangeRegistry); - protocolSession.addChannel(channel); - AMQFrame response = ChannelOpenOkBody.createAMQFrame(evt.getChannelId()); - protocolSession.writeFrame(response); - } -} diff --git a/java/broker/src/org/apache/qpid/server/handler/ConnectionCloseMethodHandler.java b/java/broker/src/org/apache/qpid/server/handler/ConnectionCloseMethodHandler.java deleted file mode 100644 index 7bdb1942d0..0000000000 --- a/java/broker/src/org/apache/qpid/server/handler/ConnectionCloseMethodHandler.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.handler; - -import org.apache.qpid.framing.ConnectionCloseBody; -import org.apache.qpid.framing.AMQFrame; -import org.apache.qpid.framing.ConnectionCloseOkBody; -import org.apache.qpid.server.state.StateAwareMethodListener; -import org.apache.qpid.server.state.AMQStateManager; -import org.apache.qpid.server.queue.QueueRegistry; -import org.apache.qpid.server.exchange.ExchangeRegistry; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.protocol.AMQMethodEvent; -import org.apache.qpid.AMQException; -import org.apache.log4j.Logger; - -public class ConnectionCloseMethodHandler implements StateAwareMethodListener -{ - private static final Logger _logger = Logger.getLogger(ConnectionCloseMethodHandler.class); - - private static ConnectionCloseMethodHandler _instance = new ConnectionCloseMethodHandler(); - - public static ConnectionCloseMethodHandler getInstance() - { - return _instance; - } - - private ConnectionCloseMethodHandler() - { - } - - public void methodReceived(AMQStateManager stateManager, QueueRegistry queueRegistry, - ExchangeRegistry exchangeRegistry, AMQProtocolSession protocolSession, - AMQMethodEvent evt) throws AMQException - { - final ConnectionCloseBody body = evt.getMethod(); - _logger.info("ConnectionClose received with reply code/reply text " + body.replyCode + "/" + - body.replyText + " for " + protocolSession); - try - { - protocolSession.closeSession(); - } - catch (Exception e) - { - _logger.error("Error closing protocol session: " + e, e); - } - final AMQFrame response = ConnectionCloseOkBody.createAMQFrame(evt.getChannelId()); - protocolSession.writeFrame(response); - } -} diff --git a/java/broker/src/org/apache/qpid/server/handler/ConnectionCloseOkMethodHandler.java b/java/broker/src/org/apache/qpid/server/handler/ConnectionCloseOkMethodHandler.java deleted file mode 100644 index cc9277593b..0000000000 --- a/java/broker/src/org/apache/qpid/server/handler/ConnectionCloseOkMethodHandler.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.handler; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.ConnectionCloseOkBody; -import org.apache.qpid.server.exchange.ExchangeRegistry; -import org.apache.qpid.server.protocol.AMQMethodEvent; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.queue.QueueRegistry; -import org.apache.qpid.server.state.AMQStateManager; -import org.apache.qpid.server.state.StateAwareMethodListener; -import org.apache.qpid.server.state.AMQState; -import org.apache.log4j.Logger; - -public class ConnectionCloseOkMethodHandler implements StateAwareMethodListener -{ - private static final Logger _logger = Logger.getLogger(ConnectionCloseOkMethodHandler.class); - - private static ConnectionCloseOkMethodHandler _instance = new ConnectionCloseOkMethodHandler(); - - public static ConnectionCloseOkMethodHandler getInstance() - { - return _instance; - } - - private ConnectionCloseOkMethodHandler() - { - } - - public void methodReceived(AMQStateManager stateManager, QueueRegistry queueRegistry, - ExchangeRegistry exchangeRegistry, AMQProtocolSession protocolSession, - AMQMethodEvent evt) throws AMQException - { - //todo should this not do more than just log the method? - _logger.info("Received Connection-close-ok"); - - try - { - stateManager.changeState(AMQState.CONNECTION_CLOSED); - protocolSession.closeSession(); - } - catch (Exception e) - { - _logger.error("Error closing protocol session: " + e, e); - } - } -} diff --git a/java/broker/src/org/apache/qpid/server/handler/ConnectionOpenMethodHandler.java b/java/broker/src/org/apache/qpid/server/handler/ConnectionOpenMethodHandler.java deleted file mode 100644 index bfcc50e1f8..0000000000 --- a/java/broker/src/org/apache/qpid/server/handler/ConnectionOpenMethodHandler.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.handler; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQFrame; -import org.apache.qpid.framing.ConnectionOpenBody; -import org.apache.qpid.framing.ConnectionOpenOkBody; -import org.apache.qpid.server.exchange.ExchangeRegistry; -import org.apache.qpid.server.protocol.AMQMethodEvent; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.queue.QueueRegistry; -import org.apache.qpid.server.state.AMQState; -import org.apache.qpid.server.state.AMQStateManager; -import org.apache.qpid.server.state.StateAwareMethodListener; - -public class ConnectionOpenMethodHandler implements StateAwareMethodListener -{ - private static ConnectionOpenMethodHandler _instance = new ConnectionOpenMethodHandler(); - - public static ConnectionOpenMethodHandler getInstance() - { - return _instance; - } - - private ConnectionOpenMethodHandler() - { - } - - private static String generateClientID() - { - return Long.toString(System.currentTimeMillis()); - } - - public void methodReceived(AMQStateManager stateManager, QueueRegistry queueRegistry, - ExchangeRegistry exchangeRegistry, AMQProtocolSession protocolSession, - AMQMethodEvent evt) throws AMQException - { - ConnectionOpenBody body = evt.getMethod(); - String contextKey = body.virtualHost; - - //todo //FIXME The virtual host must be validated by the server for the connection to open-ok - // See Spec (0.8.2). Section 3.1.2 Virtual Hosts - if (contextKey == null) - { - contextKey = generateClientID(); - } - protocolSession.setContextKey(contextKey); - AMQFrame response = ConnectionOpenOkBody.createAMQFrame((short)0, contextKey); - stateManager.changeState(AMQState.CONNECTION_OPEN); - protocolSession.writeFrame(response); - } -} diff --git a/java/broker/src/org/apache/qpid/server/handler/ConnectionSecureOkMethodHandler.java b/java/broker/src/org/apache/qpid/server/handler/ConnectionSecureOkMethodHandler.java deleted file mode 100644 index c858d25e2d..0000000000 --- a/java/broker/src/org/apache/qpid/server/handler/ConnectionSecureOkMethodHandler.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.handler; - -import org.apache.qpid.AMQException; -import org.apache.qpid.AMQChannelException; -import org.apache.qpid.protocol.AMQConstant; -import org.apache.qpid.framing.*; -import org.apache.qpid.server.exchange.ExchangeRegistry; -import org.apache.qpid.server.protocol.AMQMethodEvent; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.protocol.HeartbeatConfig; -import org.apache.qpid.server.queue.QueueRegistry; -import org.apache.qpid.server.state.AMQState; -import org.apache.qpid.server.state.AMQStateManager; -import org.apache.qpid.server.state.StateAwareMethodListener; -import org.apache.qpid.server.security.auth.AuthenticationManager; -import org.apache.qpid.server.security.auth.AuthenticationResult; -import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.log4j.Logger; - -import javax.security.sasl.SaslServer; -import javax.security.sasl.SaslException; - -public class ConnectionSecureOkMethodHandler implements StateAwareMethodListener -{ - private static final Logger _logger = Logger.getLogger(ConnectionSecureOkMethodHandler.class); - - private static ConnectionSecureOkMethodHandler _instance = new ConnectionSecureOkMethodHandler(); - - public static ConnectionSecureOkMethodHandler getInstance() - { - return _instance; - } - - private ConnectionSecureOkMethodHandler() - { - } - - public void methodReceived(AMQStateManager stateManager, QueueRegistry queueRegistry, - ExchangeRegistry exchangeRegistry, AMQProtocolSession protocolSession, - AMQMethodEvent evt) throws AMQException - { - ConnectionSecureOkBody body = evt.getMethod(); - - AuthenticationManager authMgr = ApplicationRegistry.getInstance().getAuthenticationManager(); - SaslServer ss = protocolSession.getSaslServer(); - if (ss == null) - { - throw new AMQException("No SASL context set up in session"); - } - - AuthenticationResult authResult = authMgr.authenticate(ss, body.response); - switch (authResult.status) - { - case ERROR: - // Can't do this as we violate protocol. Need to send Close - // throw new AMQException(AMQConstant.NOT_ALLOWED.getCode(), AMQConstant.NOT_ALLOWED.getName()); - _logger.info("Authentication failed"); - stateManager.changeState(AMQState.CONNECTION_CLOSING); - AMQFrame close = ConnectionCloseBody.createAMQFrame(0, AMQConstant.NOT_ALLOWED.getCode(), - AMQConstant.NOT_ALLOWED.getName(), - ConnectionCloseBody.CLASS_ID, - ConnectionCloseBody.METHOD_ID); - protocolSession.writeFrame(close); - disposeSaslServer(protocolSession); - break; - case SUCCESS: - _logger.info("Connected as: " + ss.getAuthorizationID()); - stateManager.changeState(AMQState.CONNECTION_NOT_TUNED); - AMQFrame tune = ConnectionTuneBody.createAMQFrame(0, Integer.MAX_VALUE, - ConnectionStartOkMethodHandler.getConfiguredFrameSize(), - HeartbeatConfig.getInstance().getDelay()); - protocolSession.writeFrame(tune); - disposeSaslServer(protocolSession); - break; - case CONTINUE: - stateManager.changeState(AMQState.CONNECTION_NOT_AUTH); - AMQFrame challenge = ConnectionSecureBody.createAMQFrame(0, authResult.challenge); - protocolSession.writeFrame(challenge); - } - } - - private void disposeSaslServer(AMQProtocolSession ps) - { - SaslServer ss = ps.getSaslServer(); - if (ss != null) - { - ps.setSaslServer(null); - try - { - ss.dispose(); - } - catch (SaslException e) - { - _logger.error("Error disposing of Sasl server: " + e); - } - } - } -} diff --git a/java/broker/src/org/apache/qpid/server/handler/ConnectionStartOkMethodHandler.java b/java/broker/src/org/apache/qpid/server/handler/ConnectionStartOkMethodHandler.java deleted file mode 100644 index 00ae547683..0000000000 --- a/java/broker/src/org/apache/qpid/server/handler/ConnectionStartOkMethodHandler.java +++ /dev/null @@ -1,130 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.handler; - -import org.apache.log4j.Logger; -import org.apache.commons.configuration.Configuration; -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQFrame; -import org.apache.qpid.framing.ConnectionSecureBody; -import org.apache.qpid.framing.ConnectionStartOkBody; -import org.apache.qpid.framing.ConnectionTuneBody; -import org.apache.qpid.server.exchange.ExchangeRegistry; -import org.apache.qpid.server.protocol.AMQMethodEvent; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.protocol.HeartbeatConfig; -import org.apache.qpid.server.queue.QueueRegistry; -import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.security.auth.AuthenticationManager; -import org.apache.qpid.server.security.auth.AuthenticationResult; -import org.apache.qpid.server.state.AMQState; -import org.apache.qpid.server.state.AMQStateManager; -import org.apache.qpid.server.state.StateAwareMethodListener; - -import javax.security.sasl.SaslException; -import javax.security.sasl.SaslServer; - - -public class ConnectionStartOkMethodHandler implements StateAwareMethodListener -{ - private static final Logger _logger = Logger.getLogger(ConnectionStartOkMethodHandler.class); - - private static ConnectionStartOkMethodHandler _instance = new ConnectionStartOkMethodHandler(); - - private static final int DEFAULT_FRAME_SIZE = 65536; - - public static StateAwareMethodListener getInstance() - { - return _instance; - } - - private ConnectionStartOkMethodHandler() - { - } - - public void methodReceived(AMQStateManager stateManager, QueueRegistry queueRegistry, - ExchangeRegistry exchangeRegistry, AMQProtocolSession protocolSession, - AMQMethodEvent evt) throws AMQException - { - final ConnectionStartOkBody body = evt.getMethod(); - _logger.info("SASL Mechanism selected: " + body.mechanism); - _logger.info("Locale selected: " + body.locale); - - AuthenticationManager authMgr = ApplicationRegistry.getInstance().getAuthenticationManager(); - - SaslServer ss = null; - try - { - ss = authMgr.createSaslServer(body.mechanism, protocolSession.getLocalFQDN()); - protocolSession.setSaslServer(ss); - - AuthenticationResult authResult = authMgr.authenticate(ss, body.response); - - switch (authResult.status) - { - case ERROR: - throw new AMQException("Authentication failed"); - case SUCCESS: - _logger.info("Connected as: " + ss.getAuthorizationID()); - stateManager.changeState(AMQState.CONNECTION_NOT_TUNED); - AMQFrame tune = ConnectionTuneBody.createAMQFrame(0, Integer.MAX_VALUE, getConfiguredFrameSize(), - HeartbeatConfig.getInstance().getDelay()); - protocolSession.writeFrame(tune); - break; - case CONTINUE: - stateManager.changeState(AMQState.CONNECTION_NOT_AUTH); - AMQFrame challenge = ConnectionSecureBody.createAMQFrame(0, authResult.challenge); - protocolSession.writeFrame(challenge); - } - } - catch (SaslException e) - { - disposeSaslServer(protocolSession); - throw new AMQException("SASL error: " + e, e); - } - } - - private void disposeSaslServer(AMQProtocolSession ps) - { - SaslServer ss = ps.getSaslServer(); - if (ss != null) - { - ps.setSaslServer(null); - try - { - ss.dispose(); - } - catch (SaslException e) - { - _logger.error("Error disposing of Sasl server: " + e); - } - } - } - - static int getConfiguredFrameSize() - { - final Configuration config = ApplicationRegistry.getInstance().getConfiguration(); - final int framesize = config.getInt("advanced.framesize", DEFAULT_FRAME_SIZE); - _logger.info("Framesize set to " + framesize); - return framesize; - } -} - diff --git a/java/broker/src/org/apache/qpid/server/handler/ConnectionTuneOkMethodHandler.java b/java/broker/src/org/apache/qpid/server/handler/ConnectionTuneOkMethodHandler.java deleted file mode 100644 index f0b4e0a515..0000000000 --- a/java/broker/src/org/apache/qpid/server/handler/ConnectionTuneOkMethodHandler.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.handler; - -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.ConnectionTuneOkBody; -import org.apache.qpid.server.exchange.ExchangeRegistry; -import org.apache.qpid.server.protocol.AMQMethodEvent; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.queue.QueueRegistry; -import org.apache.qpid.server.state.AMQState; -import org.apache.qpid.server.state.AMQStateManager; -import org.apache.qpid.server.state.StateAwareMethodListener; - -public class ConnectionTuneOkMethodHandler implements StateAwareMethodListener -{ - private static final Logger _logger = Logger.getLogger(ConnectionTuneOkMethodHandler.class); - - private static ConnectionTuneOkMethodHandler _instance = new ConnectionTuneOkMethodHandler(); - - public static ConnectionTuneOkMethodHandler getInstance() - { - return _instance; - } - - public void methodReceived(AMQStateManager stateManager, QueueRegistry queueRegistry, - ExchangeRegistry exchangeRegistry, AMQProtocolSession protocolSession, - AMQMethodEvent evt) throws AMQException - { - ConnectionTuneOkBody body = evt.getMethod(); - if (_logger.isDebugEnabled()) - { - _logger.debug(body); - } - stateManager.changeState(AMQState.CONNECTION_NOT_OPENED); - protocolSession.initHeartbeats(body.heartbeat); - } -} diff --git a/java/broker/src/org/apache/qpid/server/handler/ExchangeDeclareHandler.java b/java/broker/src/org/apache/qpid/server/handler/ExchangeDeclareHandler.java deleted file mode 100644 index b7c75e290a..0000000000 --- a/java/broker/src/org/apache/qpid/server/handler/ExchangeDeclareHandler.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.handler; - -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQFrame; -import org.apache.qpid.framing.ExchangeDeclareBody; -import org.apache.qpid.framing.ExchangeDeclareOkBody; -import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.server.exchange.ExchangeRegistry; -import org.apache.qpid.server.exchange.ExchangeFactory; -import org.apache.qpid.server.protocol.AMQMethodEvent; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.queue.QueueRegistry; -import org.apache.qpid.server.state.AMQStateManager; -import org.apache.qpid.server.state.StateAwareMethodListener; -import org.apache.qpid.server.registry.ApplicationRegistry; - -public class ExchangeDeclareHandler implements StateAwareMethodListener -{ - private static final Logger _logger = Logger.getLogger(ExchangeDeclareHandler.class); - - private static final ExchangeDeclareHandler _instance = new ExchangeDeclareHandler(); - - public static ExchangeDeclareHandler getInstance() - { - return _instance; - } - - private final ExchangeFactory exchangeFactory; - - private ExchangeDeclareHandler() - { - exchangeFactory = ApplicationRegistry.getInstance().getExchangeFactory(); - } - - public void methodReceived(AMQStateManager stateManager, QueueRegistry queueRegistry, - ExchangeRegistry exchangeRegistry, AMQProtocolSession protocolSession, - AMQMethodEvent evt) throws AMQException - { - final ExchangeDeclareBody body = evt.getMethod(); - if (_logger.isDebugEnabled()) - { - _logger.debug("Request to declare exchange of type " + body.type + " with name " + body.exchange); - } - synchronized(exchangeRegistry) - { - Exchange exchange = exchangeRegistry.getExchange(body.exchange); - - if (exchange == null) - { - exchange = exchangeFactory.createExchange(body.exchange, body.type, body.durable, - body.passive, body.ticket); - exchangeRegistry.registerExchange(exchange); - } - } - if(!body.nowait) - { - AMQFrame response = ExchangeDeclareOkBody.createAMQFrame(evt.getChannelId()); - protocolSession.writeFrame(response); - } - } -} diff --git a/java/broker/src/org/apache/qpid/server/handler/ExchangeDeleteHandler.java b/java/broker/src/org/apache/qpid/server/handler/ExchangeDeleteHandler.java deleted file mode 100644 index 93ef902190..0000000000 --- a/java/broker/src/org/apache/qpid/server/handler/ExchangeDeleteHandler.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.handler; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQFrame; -import org.apache.qpid.framing.ExchangeDeleteBody; -import org.apache.qpid.framing.ExchangeDeleteOkBody; -import org.apache.qpid.server.exchange.ExchangeInUseException; -import org.apache.qpid.server.exchange.ExchangeRegistry; -import org.apache.qpid.server.protocol.AMQMethodEvent; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.queue.QueueRegistry; -import org.apache.qpid.server.state.AMQStateManager; -import org.apache.qpid.server.state.StateAwareMethodListener; - -public class ExchangeDeleteHandler implements StateAwareMethodListener -{ - private static final ExchangeDeleteHandler _instance = new ExchangeDeleteHandler(); - - public static ExchangeDeleteHandler getInstance() - { - return _instance; - } - - private ExchangeDeleteHandler() - { - } - - public void methodReceived(AMQStateManager stateManager, QueueRegistry queueRegistry, - ExchangeRegistry exchangeRegistry, AMQProtocolSession protocolSession, - AMQMethodEvent evt) throws AMQException - { - ExchangeDeleteBody body = evt.getMethod(); - try - { - exchangeRegistry.unregisterExchange(body.exchange, body.ifUnused); - AMQFrame response = ExchangeDeleteOkBody.createAMQFrame(evt.getChannelId()); - protocolSession.writeFrame(response); - } - catch (ExchangeInUseException e) - { - // TODO: sort out consistent channel close mechanism that does all clean up etc. - } - - } -} diff --git a/java/broker/src/org/apache/qpid/server/handler/OnCurrentThreadExecutor.java b/java/broker/src/org/apache/qpid/server/handler/OnCurrentThreadExecutor.java deleted file mode 100644 index ac516b6133..0000000000 --- a/java/broker/src/org/apache/qpid/server/handler/OnCurrentThreadExecutor.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.handler; - -import java.util.concurrent.Executor; - -/** - * An executor that executes the task on the current thread. - */ -public class OnCurrentThreadExecutor implements Executor -{ - public void execute(Runnable command) - { - command.run(); - } -} diff --git a/java/broker/src/org/apache/qpid/server/handler/QueueBindHandler.java b/java/broker/src/org/apache/qpid/server/handler/QueueBindHandler.java deleted file mode 100644 index cf9e40a660..0000000000 --- a/java/broker/src/org/apache/qpid/server/handler/QueueBindHandler.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.handler; - -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; -import org.apache.qpid.protocol.AMQConstant; -import org.apache.qpid.framing.AMQFrame; -import org.apache.qpid.framing.QueueBindBody; -import org.apache.qpid.framing.QueueBindOkBody; -import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.server.exchange.ExchangeRegistry; -import org.apache.qpid.server.protocol.AMQMethodEvent; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.queue.QueueRegistry; -import org.apache.qpid.server.state.AMQStateManager; -import org.apache.qpid.server.state.StateAwareMethodListener; - -public class QueueBindHandler implements StateAwareMethodListener -{ - private static final Logger _log = Logger.getLogger(QueueBindHandler.class); - - private static final QueueBindHandler _instance = new QueueBindHandler(); - - public static QueueBindHandler getInstance() - { - return _instance; - } - - private QueueBindHandler() - { - } - - public void methodReceived(AMQStateManager stateManager, QueueRegistry queueRegistry, - ExchangeRegistry exchangeRegistry, AMQProtocolSession protocolSession, - AMQMethodEvent evt) throws AMQException - { - final QueueBindBody body = evt.getMethod(); - final AMQQueue queue; - if (body.queue == null) - { - queue = protocolSession.getChannel(evt.getChannelId()).getDefaultQueue(); - if (queue == null) - { - throw new AMQException("No default queue defined on channel and queue was null"); - } - if (body.routingKey == null) - { - body.routingKey = queue.getName(); - } - } - else - { - queue = queueRegistry.getQueue(body.queue); - } - - if (queue == null) - { - throw body.getChannelException(AMQConstant.NOT_FOUND.getCode(), "Queue " + body.queue + " does not exist."); - } - final Exchange exch = exchangeRegistry.getExchange(body.exchange); - if (exch == null) - { - throw body.getChannelException(AMQConstant.NOT_FOUND.getCode(), "Exchange " + body.exchange + " does not exist."); - } - exch.registerQueue(body.routingKey, queue, body.arguments); - queue.bind(body.routingKey, exch); - if (_log.isInfoEnabled()) - { - _log.info("Binding queue " + queue + " to exchange " + exch + " with routing key " + body.routingKey); - } - if (!body.nowait) - { - final AMQFrame response = QueueBindOkBody.createAMQFrame(evt.getChannelId()); - protocolSession.writeFrame(response); - } - } -} diff --git a/java/broker/src/org/apache/qpid/server/handler/QueueDeclareHandler.java b/java/broker/src/org/apache/qpid/server/handler/QueueDeclareHandler.java deleted file mode 100644 index b7004de2a9..0000000000 --- a/java/broker/src/org/apache/qpid/server/handler/QueueDeclareHandler.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.handler; - -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; -import org.apache.qpid.configuration.Configured; -import org.apache.qpid.framing.AMQFrame; -import org.apache.qpid.framing.QueueDeclareBody; -import org.apache.qpid.framing.QueueDeclareOkBody; -import org.apache.qpid.server.exchange.ExchangeRegistry; -import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.server.protocol.AMQMethodEvent; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.queue.QueueRegistry; -import org.apache.qpid.server.state.AMQStateManager; -import org.apache.qpid.server.state.StateAwareMethodListener; -import org.apache.qpid.server.configuration.Configurator; -import org.apache.qpid.server.store.MessageStore; -import org.apache.qpid.server.registry.ApplicationRegistry; - -import java.text.MessageFormat; -import java.util.concurrent.atomic.AtomicInteger; - -public class QueueDeclareHandler implements StateAwareMethodListener -{ - private static final Logger _log = Logger.getLogger(QueueDeclareHandler.class); - - private static final QueueDeclareHandler _instance = new QueueDeclareHandler(); - - public static QueueDeclareHandler getInstance() - { - return _instance; - } - - @Configured(path = "queue.auto_register", defaultValue = "false") - public boolean autoRegister; - - private final AtomicInteger _counter = new AtomicInteger(); - - private final MessageStore _store; - - protected QueueDeclareHandler() - { - Configurator.configure(this); - _store = ApplicationRegistry.getInstance().getMessageStore(); - } - - public void methodReceived(AMQStateManager stateManager, QueueRegistry queueRegistry, - ExchangeRegistry exchangeRegistry, AMQProtocolSession protocolSession, - AMQMethodEvent evt) throws AMQException - { - QueueDeclareBody body = evt.getMethod(); - - // if we aren't given a queue name, we create one which we return to the client - if (body.queue == null) - { - body.queue = createName(); - } - //TODO: do we need to check that the queue already exists with exactly the same "configuration"? - - synchronized (queueRegistry) - { - AMQQueue queue; - if ((queue = queueRegistry.getQueue(body.queue)) == null) - { - queue = createQueue(body, queueRegistry, protocolSession); - if (queue.isDurable() && !queue.isAutoDelete()) - { - _store.createQueue(queue); - } - queueRegistry.registerQueue(queue); - if (autoRegister) - { - Exchange defaultExchange = exchangeRegistry.getExchange("amq.direct"); - defaultExchange.registerQueue(body.queue, queue, null); - queue.bind(body.queue, defaultExchange); - _log.info("Queue " + body.queue + " bound to default exchange"); - } - } - //set this as the default queue on the channel: - protocolSession.getChannel(evt.getChannelId()).setDefaultQueue(queue); - } - if (!body.nowait) - { - AMQFrame response = QueueDeclareOkBody.createAMQFrame(evt.getChannelId(), body.queue, 0L, 0L); - _log.info("Queue " + body.queue + " declared successfully"); - protocolSession.writeFrame(response); - } - } - - protected String createName() - { - return "tmp_" + pad(_counter.incrementAndGet()); - } - - protected static String pad(int value) - { - return MessageFormat.format("{0,number,0000000000000}", value); - } - - protected AMQQueue createQueue(QueueDeclareBody body, QueueRegistry registry, AMQProtocolSession session) - throws AMQException - { - String owner = body.exclusive ? session.getContextKey() : null; - return new AMQQueue(body.queue, body.durable, owner, body.autoDelete, registry); - } -} diff --git a/java/broker/src/org/apache/qpid/server/handler/QueueDeleteHandler.java b/java/broker/src/org/apache/qpid/server/handler/QueueDeleteHandler.java deleted file mode 100644 index 0dbc54f29b..0000000000 --- a/java/broker/src/org/apache/qpid/server/handler/QueueDeleteHandler.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.handler; - -import org.apache.qpid.server.state.StateAwareMethodListener; -import org.apache.qpid.server.state.AMQStateManager; -import org.apache.qpid.server.queue.QueueRegistry; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.exchange.ExchangeRegistry; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.protocol.AMQMethodEvent; -import org.apache.qpid.server.store.MessageStore; -import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.framing.QueueDeleteBody; -import org.apache.qpid.framing.QueueDeleteOkBody; -import org.apache.qpid.AMQException; - -public class QueueDeleteHandler implements StateAwareMethodListener -{ - private static final QueueDeleteHandler _instance = new QueueDeleteHandler(); - - public static QueueDeleteHandler getInstance() - { - return _instance; - } - - private final boolean _failIfNotFound; - private final MessageStore _store; - - public QueueDeleteHandler() - { - this(true); - } - - public QueueDeleteHandler(boolean failIfNotFound) - { - _failIfNotFound = failIfNotFound; - _store = ApplicationRegistry.getInstance().getMessageStore(); - - } - - public void methodReceived(AMQStateManager stateMgr, QueueRegistry queues, ExchangeRegistry exchanges, AMQProtocolSession session, AMQMethodEvent evt) throws AMQException - { - QueueDeleteBody body = evt.getMethod(); - AMQQueue queue; - if(body.queue == null) - { - queue = session.getChannel(evt.getChannelId()).getDefaultQueue(); - } - else - { - queue = queues.getQueue(body.queue); - } - - if(queue == null) - { - if(_failIfNotFound) - { - throw body.getChannelException(404, "Queue " + body.queue + " does not exist."); - } - } - else - { - int purged = queue.delete(body.ifUnused, body.ifEmpty); - _store.removeQueue(queue.getName()); - session.writeFrame(QueueDeleteOkBody.createAMQFrame(evt.getChannelId(), purged)); - } - } -} diff --git a/java/broker/src/org/apache/qpid/server/handler/TxCommitHandler.java b/java/broker/src/org/apache/qpid/server/handler/TxCommitHandler.java deleted file mode 100644 index ac864cab6c..0000000000 --- a/java/broker/src/org/apache/qpid/server/handler/TxCommitHandler.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.handler; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.TxCommitBody; -import org.apache.qpid.framing.TxCommitOkBody; -import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.server.exchange.ExchangeRegistry; -import org.apache.qpid.server.protocol.AMQMethodEvent; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.queue.QueueRegistry; -import org.apache.qpid.server.state.AMQStateManager; -import org.apache.qpid.server.state.StateAwareMethodListener; - -public class TxCommitHandler implements StateAwareMethodListener -{ - private static TxCommitHandler _instance = new TxCommitHandler(); - - public static TxCommitHandler getInstance() - { - return _instance; - } - - private TxCommitHandler() - { - } - - public void methodReceived(AMQStateManager stateManager, QueueRegistry queueRegistry, - ExchangeRegistry exchangeRegistry, AMQProtocolSession protocolSession, - AMQMethodEvent evt) throws AMQException - { - - try{ - AMQChannel channel = protocolSession.getChannel(evt.getChannelId()); - channel.commit(); - protocolSession.writeFrame(TxCommitOkBody.createAMQFrame(evt.getChannelId())); - channel.processReturns(protocolSession); - }catch(AMQException e){ - throw evt.getMethod().getChannelException(e.getErrorCode(), "Failed to commit: " + e.getMessage()); - } - } -} diff --git a/java/broker/src/org/apache/qpid/server/handler/TxRollbackHandler.java b/java/broker/src/org/apache/qpid/server/handler/TxRollbackHandler.java deleted file mode 100644 index 475f6ecacf..0000000000 --- a/java/broker/src/org/apache/qpid/server/handler/TxRollbackHandler.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.handler; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.TxRollbackBody; -import org.apache.qpid.framing.TxRollbackOkBody; -import org.apache.qpid.server.exchange.ExchangeRegistry; -import org.apache.qpid.server.protocol.AMQMethodEvent; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.queue.QueueRegistry; -import org.apache.qpid.server.state.AMQStateManager; -import org.apache.qpid.server.state.StateAwareMethodListener; -import org.apache.qpid.server.AMQChannel; - -public class TxRollbackHandler implements StateAwareMethodListener -{ - private static TxRollbackHandler _instance = new TxRollbackHandler(); - - public static TxRollbackHandler getInstance() - { - return _instance; - } - - private TxRollbackHandler() - { - } - - public void methodReceived(AMQStateManager stateManager, QueueRegistry queueRegistry, - ExchangeRegistry exchangeRegistry, AMQProtocolSession protocolSession, - AMQMethodEvent evt) throws AMQException - { - try{ - AMQChannel channel = protocolSession.getChannel(evt.getChannelId()); - channel.rollback(); - protocolSession.writeFrame(TxRollbackOkBody.createAMQFrame(evt.getChannelId())); - //Now resend all the unacknowledged messages back to the original subscribers. - //(Must be done after the TxnRollback-ok response). - channel.resend(protocolSession); - }catch(AMQException e){ - throw evt.getMethod().getChannelException(e.getErrorCode(), "Failed to rollback: " + e.getMessage()); - } - } -} diff --git a/java/broker/src/org/apache/qpid/server/handler/TxSelectHandler.java b/java/broker/src/org/apache/qpid/server/handler/TxSelectHandler.java deleted file mode 100644 index c30bc7d66f..0000000000 --- a/java/broker/src/org/apache/qpid/server/handler/TxSelectHandler.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.handler; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.TxSelectBody; -import org.apache.qpid.framing.TxSelectOkBody; -import org.apache.qpid.server.exchange.ExchangeRegistry; -import org.apache.qpid.server.protocol.AMQMethodEvent; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.queue.QueueRegistry; -import org.apache.qpid.server.state.AMQStateManager; -import org.apache.qpid.server.state.StateAwareMethodListener; - -public class TxSelectHandler implements StateAwareMethodListener -{ - private static TxSelectHandler _instance = new TxSelectHandler(); - - public static TxSelectHandler getInstance() - { - return _instance; - } - - private TxSelectHandler() - { - } - - public void methodReceived(AMQStateManager stateManager, QueueRegistry queueRegistry, - ExchangeRegistry exchangeRegistry, AMQProtocolSession protocolSession, - AMQMethodEvent evt) throws AMQException - { - protocolSession.getChannel(evt.getChannelId()).setTransactional(true); - protocolSession.writeFrame(TxSelectOkBody.createAMQFrame(evt.getChannelId())); - } -} diff --git a/java/broker/src/org/apache/qpid/server/jms/JmsConsumer.java b/java/broker/src/org/apache/qpid/server/jms/JmsConsumer.java deleted file mode 100644 index 41786e84ba..0000000000 --- a/java/broker/src/org/apache/qpid/server/jms/JmsConsumer.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.jms; - -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.AMQException; - -public class JmsConsumer -{ - private int _prefetchValue; - - private PrefetchUnits _prefetchUnits; - - private boolean _noLocal; - - private boolean _autoAck; - - private boolean _exclusive; - - private AMQProtocolSession _protocolSession; - - public enum PrefetchUnits - { - OCTETS, - MESSAGES - } - - public int getPrefetchValue() - { - return _prefetchValue; - } - - public void setPrefetchValue(int prefetchValue) - { - _prefetchValue = prefetchValue; - } - - public PrefetchUnits getPrefetchUnits() - { - return _prefetchUnits; - } - - public void setPrefetchUnits(PrefetchUnits prefetchUnits) - { - _prefetchUnits = prefetchUnits; - } - - public boolean isNoLocal() - { - return _noLocal; - } - - public void setNoLocal(boolean noLocal) - { - _noLocal = noLocal; - } - - public boolean isAutoAck() - { - return _autoAck; - } - - public void setAutoAck(boolean autoAck) - { - _autoAck = autoAck; - } - - public boolean isExclusive() - { - return _exclusive; - } - - public void setExclusive(boolean exclusive) - { - _exclusive = exclusive; - } - - public AMQProtocolSession getProtocolSession() - { - return _protocolSession; - } - - public void setProtocolSession(AMQProtocolSession protocolSession) - { - _protocolSession = protocolSession; - } - - public void deliverMessage() throws AMQException - { - - } -} diff --git a/java/broker/src/org/apache/qpid/server/management/AMQManagedObject.java b/java/broker/src/org/apache/qpid/server/management/AMQManagedObject.java deleted file mode 100644 index a2c2bd62a2..0000000000 --- a/java/broker/src/org/apache/qpid/server/management/AMQManagedObject.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.management; - -import javax.management.ListenerNotFoundException; -import javax.management.MBeanInfo; -import javax.management.MBeanNotificationInfo; -import javax.management.NotCompliantMBeanException; -import javax.management.NotificationBroadcaster; -import javax.management.NotificationBroadcasterSupport; -import javax.management.NotificationFilter; -import javax.management.NotificationListener; - -/** - * This class provides additinal feature of Notification Broadcaster to the - * DefaultManagedObject. - * @author Bhupendra Bhardwaj - * @version 0.1 - */ -public abstract class AMQManagedObject extends DefaultManagedObject - implements NotificationBroadcaster -{ - /** - * broadcaster support class - */ - protected NotificationBroadcasterSupport _broadcaster = new NotificationBroadcasterSupport(); - - /** - * sequence number for notifications - */ - protected long _notificationSequenceNumber = 0; - - protected MBeanInfo _mbeanInfo; - - protected AMQManagedObject(Class managementInterface, String typeName) - throws NotCompliantMBeanException - { - super(managementInterface, typeName); - buildMBeanInfo(); - } - - @Override - public MBeanInfo getMBeanInfo() - { - return _mbeanInfo; - } - - private void buildMBeanInfo() throws NotCompliantMBeanException - { - _mbeanInfo = new MBeanInfo(this.getClass().getName(), - MBeanIntrospector.getMBeanDescription(this.getClass()), - MBeanIntrospector.getMBeanAttributesInfo(getManagementInterface()), - MBeanIntrospector.getMBeanConstructorsInfo(this.getClass()), - MBeanIntrospector.getMBeanOperationsInfo(getManagementInterface()), - this.getNotificationInfo()); - } - - - - // notification broadcaster implementation - - public void addNotificationListener(NotificationListener listener, - NotificationFilter filter, - Object handback) - { - _broadcaster.addNotificationListener(listener, filter, handback); - } - - public void removeNotificationListener(NotificationListener listener) - throws ListenerNotFoundException - { - _broadcaster.removeNotificationListener(listener); - } - - public MBeanNotificationInfo[] getNotificationInfo() - { - return null; - } -} diff --git a/java/broker/src/org/apache/qpid/server/management/DefaultManagedObject.java b/java/broker/src/org/apache/qpid/server/management/DefaultManagedObject.java deleted file mode 100644 index 311eb8add9..0000000000 --- a/java/broker/src/org/apache/qpid/server/management/DefaultManagedObject.java +++ /dev/null @@ -1,171 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.management; - -import org.apache.qpid.AMQException; -import org.apache.qpid.server.registry.ApplicationRegistry; - -import javax.management.JMException; -import javax.management.MalformedObjectNameException; -import javax.management.NotCompliantMBeanException; -import javax.management.ObjectName; -import javax.management.StandardMBean; - -/** - * Provides implementation of the boilerplate ManagedObject interface. Most managed objects should find it useful - * to extend this class rather than implementing ManagedObject from scratch. - * - */ -public abstract class DefaultManagedObject extends StandardMBean implements ManagedObject -{ - private Class _managementInterface; - - private String _typeName; - - protected DefaultManagedObject(Class managementInterface, String typeName) - throws NotCompliantMBeanException - { - super(managementInterface); - _managementInterface = managementInterface; - _typeName = typeName; - } - - public String getType() - { - return _typeName; - } - - public Class getManagementInterface() - { - return _managementInterface; - } - - public ManagedObject getParentObject() - { - return null; - } - - public void register() throws AMQException - { - try - { - ApplicationRegistry.getInstance().getManagedObjectRegistry().registerObject(this); - } - catch (JMException e) - { - throw new AMQException("Error registering managed object " + this + ": " + e, e); - } - } - - public void unregister() throws AMQException - { - try - { - ApplicationRegistry.getInstance().getManagedObjectRegistry().unregisterObject(this); - } - catch (JMException e) - { - throw new AMQException("Error unregistering managed object: " + this + ": " + e, e); - } - } - - public String toString() - { - return getObjectInstanceName() + "[" + getType() + "]"; - } - - /** - * Created the ObjectName as per the JMX Specs - * @return ObjectName - * @throws MalformedObjectNameException - */ - public ObjectName getObjectName() - throws MalformedObjectNameException - { - String name = getObjectInstanceName(); - StringBuffer objectName = new StringBuffer(ManagedObject.DOMAIN); - - objectName.append(":type="); - objectName.append(getHierarchicalType(this)); - - objectName.append(","); - objectName.append(getHierarchicalName(this)); - objectName.append("name=").append(name); - - return new ObjectName(objectName.toString()); - } - - private String getHierarchicalType(ManagedObject obj) - { - String parentType = null; - if (obj.getParentObject() != null) - { - parentType = getHierarchicalType(obj.getParentObject()).toString(); - return parentType + "." + obj.getType(); - } - else - return obj.getType(); - } - - private String getHierarchicalName(ManagedObject obj) - { - String parentName = null; - if (obj.getParentObject() != null) - { - parentName = obj.getParentObject().getType() + "=" + - obj.getParentObject().getObjectInstanceName() + ","+ - getHierarchicalName(obj.getParentObject()); - - return parentName; - } - else - return ""; - } - - protected static StringBuffer jmxEncode(StringBuffer jmxName, int attrPos) - { - for (int i = attrPos; i < jmxName.length(); i++) - { - if (jmxName.charAt(i) == ',') - { - jmxName.setCharAt(i, ';'); - } - else if (jmxName.charAt(i) == ':') - { - jmxName.setCharAt(i, '-'); - } - else if (jmxName.charAt(i) == '?' || - jmxName.charAt(i) == '*' || - jmxName.charAt(i) == '\\') - { - jmxName.insert(i, '\\'); - i++; - } - else if (jmxName.charAt(i) == '\n') - { - jmxName.insert(i, '\\'); - i++; - jmxName.setCharAt(i, 'n'); - } - } - return jmxName; - } -} \ No newline at end of file diff --git a/java/broker/src/org/apache/qpid/server/management/JMXManagedObjectRegistry.java b/java/broker/src/org/apache/qpid/server/management/JMXManagedObjectRegistry.java deleted file mode 100644 index 140dbc31bb..0000000000 --- a/java/broker/src/org/apache/qpid/server/management/JMXManagedObjectRegistry.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.management; - -import org.apache.log4j.Logger; - -import javax.management.JMException; -import javax.management.MBeanServer; -import java.lang.management.ManagementFactory; - -public class JMXManagedObjectRegistry implements ManagedObjectRegistry -{ - private static final Logger _log = Logger.getLogger(JMXManagedObjectRegistry.class); - - private final MBeanServer _mbeanServer; - - public JMXManagedObjectRegistry() - { - _log.info("Initialising managed object registry using platform MBean server"); - // we use the platform MBean server currently but this must be changed or at least be configuurable - _mbeanServer = ManagementFactory.getPlatformMBeanServer(); - } - - public void registerObject(ManagedObject managedObject) throws JMException - { - _mbeanServer.registerMBean(managedObject, managedObject.getObjectName()); - } - - public void unregisterObject(ManagedObject managedObject) throws JMException - { - _mbeanServer.unregisterMBean(managedObject.getObjectName()); - } - -} \ No newline at end of file diff --git a/java/broker/src/org/apache/qpid/server/management/MBeanAttribute.java b/java/broker/src/org/apache/qpid/server/management/MBeanAttribute.java deleted file mode 100644 index a2e387a9e0..0000000000 --- a/java/broker/src/org/apache/qpid/server/management/MBeanAttribute.java +++ /dev/null @@ -1,42 +0,0 @@ -package org.apache.qpid.server.management; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Inherited; -import java.lang.annotation.Target; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ - -/** - * Annotation for MBean attributes. This should be used with getter or setter - * methods of attributes. - * @author Bhupendra Bhardwaj - * @version 0.1 - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.METHOD) -@Inherited -public @interface MBeanAttribute -{ - String name(); - String description(); -} diff --git a/java/broker/src/org/apache/qpid/server/management/MBeanConstructor.java b/java/broker/src/org/apache/qpid/server/management/MBeanConstructor.java deleted file mode 100644 index c2cafcd387..0000000000 --- a/java/broker/src/org/apache/qpid/server/management/MBeanConstructor.java +++ /dev/null @@ -1,40 +0,0 @@ -package org.apache.qpid.server.management; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Inherited; -import java.lang.annotation.Target; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ - -/** - * Annotation for MBean constructors. - * @author Bhupendra Bhardwaj - * @version 0.1 - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.CONSTRUCTOR) -@Inherited -public @interface MBeanConstructor -{ - String value(); -} diff --git a/java/broker/src/org/apache/qpid/server/management/MBeanDescription.java b/java/broker/src/org/apache/qpid/server/management/MBeanDescription.java deleted file mode 100644 index e25ceeab5c..0000000000 --- a/java/broker/src/org/apache/qpid/server/management/MBeanDescription.java +++ /dev/null @@ -1,39 +0,0 @@ -package org.apache.qpid.server.management; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Inherited; -import java.lang.annotation.Target; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ - -/** - * Annotation for MBean class. - * @author Bhupendra Bhardwaj - * @version 0.1 - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.TYPE) -@Inherited -public @interface MBeanDescription { - String value(); -} diff --git a/java/broker/src/org/apache/qpid/server/management/MBeanIntrospector.java b/java/broker/src/org/apache/qpid/server/management/MBeanIntrospector.java deleted file mode 100644 index b8235a0808..0000000000 --- a/java/broker/src/org/apache/qpid/server/management/MBeanIntrospector.java +++ /dev/null @@ -1,388 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.management; - -import javax.management.MBeanAttributeInfo; -import javax.management.MBeanConstructorInfo; -import javax.management.MBeanOperationInfo; -import javax.management.MBeanParameterInfo; -import javax.management.NotCompliantMBeanException; -import java.lang.annotation.Annotation; -import java.lang.reflect.Constructor; -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.List; - -/** - * This class is a utility class to introspect the MBean class and the management - * interface class for various purposes. - * @author Bhupendra Bhardwaj - * @version 0.1 - */ -class MBeanIntrospector { - - private static final String _defaultAttributeDescription = "Management attribute"; - private static final String _defaultOerationDescription = "Management operation"; - private static final String _defaultConstructorDescription = "MBean constructor"; - private static final String _defaultMbeanDescription = "Management interface of the MBean"; - - /** - * Introspects the management interface class for MBean attributes. - * @param interfaceClass - * @return MBeanAttributeInfo[] - * @throws NotCompliantMBeanException - */ - static MBeanAttributeInfo[] getMBeanAttributesInfo(Class interfaceClass) - throws NotCompliantMBeanException - { - List attributesList = new ArrayList(); - - /** - * Using reflection, all methods of the managemetn interface will be analysed, - * and MBeanInfo will be created. - */ - for (Method method : interfaceClass.getMethods()) - { - int argCount = method.getParameterTypes().length; - String name = method.getName(); - Class resultType = method.getReturnType(); - MBeanAttributeInfo attributeInfo = null; - - if (isAttributeGetterMethod(method)) - { - String desc = getAttributeDescription(method); - attributeInfo = new MBeanAttributeInfo(name.substring(3), - resultType.getName(), - desc, - true, - false, - false); - int index = getIndexIfAlreadyExists(attributeInfo, attributesList); - if (index == -1) - { - attributesList.add(attributeInfo); - } - else - { - attributeInfo = new MBeanAttributeInfo(name.substring(3), - resultType.getName(), - desc, - true, - true, - false); - attributesList.set(index, attributeInfo); - } - } - else if (isAttributeSetterMethod(method)) - { - String desc = getAttributeDescription(method); - attributeInfo = new MBeanAttributeInfo(name.substring(3), - method.getParameterTypes()[0].getName(), - desc, - false, - true, - false); - int index = getIndexIfAlreadyExists(attributeInfo, attributesList); - if (index == -1) - { - attributesList.add(attributeInfo); - } - else - { - attributeInfo = new MBeanAttributeInfo(name.substring(3), - method.getParameterTypes()[0].getName(), - desc, - true, - true, - false); - attributesList.set(index, attributeInfo); - } - } - else if (isAttributeBoolean(method)) - { - attributeInfo = new MBeanAttributeInfo(name.substring(2), - resultType.getName(), - getAttributeDescription(method), - true, - false, - true); - attributesList.add(attributeInfo); - } - } - - return attributesList.toArray(new MBeanAttributeInfo[0]); - } - - /** - * Introspects the management interface class for management operations. - * @param interfaceClass - * @return MBeanOperationInfo[] - */ - static MBeanOperationInfo[] getMBeanOperationsInfo(Class interfaceClass) - { - List operationsList = new ArrayList(); - - for (Method method : interfaceClass.getMethods()) - { - if (!isAttributeGetterMethod(method) && - !isAttributeSetterMethod(method) && - !isAttributeBoolean(method)) - { - operationsList.add(getOperationInfo(method)); - } - } - - return operationsList.toArray(new MBeanOperationInfo[0]); - } - - /** - * Checks if the method is an attribute getter method. - * @param method - * @return true if the method is an attribute getter method. - */ - private static boolean isAttributeGetterMethod(Method method) - { - if (!(method.getName().equals("get")) && - method.getName().startsWith("get") && - method.getParameterTypes().length == 0 && - !method.getReturnType().equals(void.class)) - { - return true; - } - - return false; - } - - /** - * Checks if the method is an attribute setter method. - * @param method - * @return true if the method is an attribute setter method. - */ - private static boolean isAttributeSetterMethod(Method method) - { - if (!(method.getName().equals("set")) && - method.getName().startsWith("set") && - method.getParameterTypes().length == 1 && - method.getReturnType().equals(void.class)) - { - return true; - } - - return false; - } - - /** - * Checks if the attribute is a boolean and the method is a isX kind og method. - * @param method - * @return true if the method is an attribute isX type of method - */ - private static boolean isAttributeBoolean(Method method) - { - if (!(method.getName().equals("is")) && - method.getName().startsWith("is") && - method.getParameterTypes().length == 0 && - method.getReturnType().equals(boolean.class)) - { - return true; - } - - return false; - } - - /** - * Helper method to retrieve the attribute index from the list of attributes. - * @param attribute - * @param list - * @return attribute index no. -1 if attribtue doesn't exist - * @throws NotCompliantMBeanException - */ - private static int getIndexIfAlreadyExists(MBeanAttributeInfo attribute, - List list) - throws NotCompliantMBeanException - { - String exceptionMsg = "Conflicting attribute methods for attribute " + attribute.getName(); - - for (MBeanAttributeInfo memberAttribute : list) - { - if (attribute.getName().equals(memberAttribute.getName())) - { - if (!attribute.getType().equals(memberAttribute.getType())) - { - throw new NotCompliantMBeanException(exceptionMsg); - } - if (attribute.isReadable() && memberAttribute.isReadable()) - { - if (attribute.isIs() != memberAttribute.isIs()) - { - throw new NotCompliantMBeanException(exceptionMsg); - } - } - - return list.indexOf(memberAttribute); - } - } - - return -1; - } - - /** - * Retrieves the attribute description from annotation - * @param attributeMethod - * @return attribute description - */ - private static String getAttributeDescription(Method attributeMethod) - { - MBeanAttribute anno = attributeMethod.getAnnotation(MBeanAttribute.class); - if (anno != null) - { - return anno.description(); - } - return _defaultAttributeDescription; - } - - /** - * Introspects the method to retrieve the operation information. - * @param operation - * @return MBeanOperationInfo - */ - private static MBeanOperationInfo getOperationInfo(Method operation) - { - MBeanOperationInfo operationInfo = null; - Class returnType = operation.getReturnType(); - - MBeanParameterInfo[] paramsInfo = getParametersInfo(operation.getParameterAnnotations(), - operation.getParameterTypes()); - - String operationDesc = _defaultOerationDescription; - int impact = MBeanOperationInfo.UNKNOWN; - - if (operation.getAnnotation(MBeanOperation.class) != null) - { - operationDesc = operation.getAnnotation(MBeanOperation.class).description(); - impact = operation.getAnnotation(MBeanOperation.class).impact(); - } - operationInfo = new MBeanOperationInfo(operation.getName(), - operationDesc, - paramsInfo, - returnType.getName(), - impact); - - return operationInfo; - } - - /** - * Constructs the parameter info. - * @param paramsAnno - * @param paramTypes - * @return MBeanParameterInfo[] - */ - private static MBeanParameterInfo[] getParametersInfo(Annotation[][] paramsAnno, - Class[] paramTypes) - { - int noOfParams = paramsAnno.length; - - MBeanParameterInfo[] paramsInfo = new MBeanParameterInfo[noOfParams]; - - for (int i = 0; i < noOfParams; i++) - { - MBeanParameterInfo paramInfo = null; - String type = paramTypes[i].getName(); - for (Annotation anno : paramsAnno[i]) - { - String name,desc; - if (MBeanOperationParameter.class.isInstance(anno)) - { - name = MBeanOperationParameter.class.cast(anno).name(); - desc = MBeanOperationParameter.class.cast(anno).description(); - paramInfo = new MBeanParameterInfo(name, type, desc); - } - } - - - if (paramInfo == null) - { - paramInfo = new MBeanParameterInfo("p " + (i + 1), type, "parameter " + (i + 1)); - } - if (paramInfo != null) - paramsInfo[i] = paramInfo; - } - - return paramsInfo; - } - - /** - * Introspects the MBean class for constructors - * @param implClass - * @return MBeanConstructorInfo[] - */ - static MBeanConstructorInfo[] getMBeanConstructorsInfo(Class implClass) - { - List constructors = new ArrayList(); - - for (Constructor cons : implClass.getConstructors()) - { - MBeanConstructorInfo constructorInfo = getMBeanConstructorInfo(cons); - //MBeanConstructorInfo constructorInfo = new MBeanConstructorInfo("desc", cons); - if (constructorInfo != null) - constructors.add(constructorInfo); - } - - return constructors.toArray(new MBeanConstructorInfo[0]); - } - - /** - * Retrieves the constructor info from given constructor. - * @param cons - * @return MBeanConstructorInfo - */ - private static MBeanConstructorInfo getMBeanConstructorInfo(Constructor cons) - { - String desc = null; - Annotation anno = cons.getAnnotation(MBeanConstructor.class); - if (anno != null && MBeanConstructor.class.isInstance(anno)) - { - desc = MBeanConstructor.class.cast(anno).value(); - } - - //MBeanParameterInfo[] paramsInfo = getParametersInfo(cons.getParameterAnnotations(), - // cons.getParameterTypes()); - - return new MBeanConstructorInfo(cons.getName(), - desc != null ? _defaultConstructorDescription : desc , - null); - } - - /** - * Retrieves the description from the annotations of given class - * @param annotatedClass - * @return class description - */ - static String getMBeanDescription(Class annotatedClass) - { - Annotation anno = annotatedClass.getAnnotation(MBeanDescription.class); - if (anno != null && MBeanDescription.class.isInstance(anno)) - { - return MBeanDescription.class.cast(anno).value(); - } - return _defaultMbeanDescription; - } - -} \ No newline at end of file diff --git a/java/broker/src/org/apache/qpid/server/management/MBeanOperation.java b/java/broker/src/org/apache/qpid/server/management/MBeanOperation.java deleted file mode 100644 index ebeccadf70..0000000000 --- a/java/broker/src/org/apache/qpid/server/management/MBeanOperation.java +++ /dev/null @@ -1,43 +0,0 @@ -package org.apache.qpid.server.management; - -import javax.management.MBeanOperationInfo; -import java.lang.annotation.ElementType; -import java.lang.annotation.Inherited; -import java.lang.annotation.Target; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ - -/** - * Annotation for MBean operations. - * @author Bhupendra Bhardwaj - * @version 0.1 - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.METHOD) -@Inherited -public @interface MBeanOperation -{ - String name(); - String description(); - int impact() default MBeanOperationInfo.INFO; -} diff --git a/java/broker/src/org/apache/qpid/server/management/MBeanOperationParameter.java b/java/broker/src/org/apache/qpid/server/management/MBeanOperationParameter.java deleted file mode 100644 index adb3c651df..0000000000 --- a/java/broker/src/org/apache/qpid/server/management/MBeanOperationParameter.java +++ /dev/null @@ -1,38 +0,0 @@ -package org.apache.qpid.server.management; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; -import java.lang.annotation.ElementType; -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ - -/** - * Annotation for MBean operation parameters. - * @author Bhupendra Bhardwaj - * @version 0.1 - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.PARAMETER) -public @interface MBeanOperationParameter { - String name(); - String description(); -} diff --git a/java/broker/src/org/apache/qpid/server/management/Managable.java b/java/broker/src/org/apache/qpid/server/management/Managable.java deleted file mode 100644 index 166a2a376d..0000000000 --- a/java/broker/src/org/apache/qpid/server/management/Managable.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.management; - -/** - * Any object that can return a related MBean should implement this interface. - * - * This enables other classes to get the managed object, which in turn is useful when - * constructing relationships between managed objects without having to maintain - * separate data structures containing MBeans. - * - */ -public interface Managable -{ - ManagedObject getManagedObject(); -} diff --git a/java/broker/src/org/apache/qpid/server/management/ManagedBroker.java b/java/broker/src/org/apache/qpid/server/management/ManagedBroker.java deleted file mode 100644 index 266fb62fd8..0000000000 --- a/java/broker/src/org/apache/qpid/server/management/ManagedBroker.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ - -package org.apache.qpid.server.management; - -import javax.management.JMException; -import javax.management.MBeanOperationInfo; -import java.io.IOException; - -/** - * The ManagedBroker is the management interface to expose management - * features of the Broker. - * - * @author Bhupendra Bhardwaj - * @version 0.1 - */ -public interface ManagedBroker -{ - static final String TYPE = "BrokerManager"; - - /** - * Creates a new Exchange. - * @param name - * @param type - * @param durable - * @param passive - * @throws IOException - * @throws JMException - */ - @MBeanOperation(name="createNewExchange", description="Creates a new Exchange", - impact= MBeanOperationInfo.ACTION) - void createNewExchange(@MBeanOperationParameter(name="name", description="Name of the new exchange")String name, - @MBeanOperationParameter(name="excahnge type", description="Type of the exchange")String type, - @MBeanOperationParameter(name="durable", description="true if the Exchang should be durable")boolean durable, - @MBeanOperationParameter(name="passive", description="true of the Exchange should be passive")boolean passive) - throws IOException, JMException; - - /** - * unregisters all the channels, queuebindings etc and unregisters - * this exchange from managed objects. - * @param exchange - * @throws IOException - * @throws JMException - */ - @MBeanOperation(name="unregisterExchange", - description="Unregisters all the related channels and queuebindings of this exchange", - impact= MBeanOperationInfo.ACTION) - void unregisterExchange(@MBeanOperationParameter(name="exchange name", description="Name of the exchange")String exchange) - throws IOException, JMException; - - /** - * Create a new Queue on the Broker server - * @param queueName - * @param durable - * @param owner - * @param autoDelete - * @throws IOException - * @throws JMException - */ - @MBeanOperation(name="createQueue", description="Create a new Queue on the Broker server", - impact= MBeanOperationInfo.ACTION) - void createQueue(@MBeanOperationParameter(name="queue name", description="Name of the new queue")String queueName, - @MBeanOperationParameter(name="durable", description="true if the queue should be durable")boolean durable, - @MBeanOperationParameter(name="owner", description="Owner name")String owner, - @MBeanOperationParameter(name="autoDelete", description="true if the queue should be auto delete") boolean autoDelete) - throws IOException, JMException; - - /** - * Unregisters the Queue bindings, removes the subscriptions and unregisters - * from the managed objects. - * @param queueName - * @throws IOException - * @throws JMException - */ - @MBeanOperation(name="deleteQueue", - description="Unregisters the Queue bindings, removes the subscriptions and deletes the queue", - impact= MBeanOperationInfo.ACTION) - void deleteQueue(@MBeanOperationParameter(name="queue name", description="Name of the queue")String queueName) - throws IOException, JMException; -} diff --git a/java/broker/src/org/apache/qpid/server/management/ManagedObject.java b/java/broker/src/org/apache/qpid/server/management/ManagedObject.java deleted file mode 100644 index f512c2dea8..0000000000 --- a/java/broker/src/org/apache/qpid/server/management/ManagedObject.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.management; - -import org.apache.qpid.AMQException; - -import javax.management.ObjectName; -import javax.management.MalformedObjectNameException; - -/** - * This should be implemented by all Managable objects. - */ -public interface ManagedObject -{ - static final String DOMAIN = "org.apache.qpid"; - - /** - * @return the name that uniquely identifies this object instance. It must be - * unique only among objects of this type at this level in the hierarchy so - * the uniqueness should not be too difficult to ensure. - */ - String getObjectInstanceName(); - - String getType(); - - Class getManagementInterface(); - - ManagedObject getParentObject(); - - void register() throws AMQException; - - void unregister() throws AMQException; - - /** - * Returns the ObjectName required for the mbeanserver registration. - * @return ObjectName - * @throws MalformedObjectNameException - */ - ObjectName getObjectName() throws MalformedObjectNameException; -} diff --git a/java/broker/src/org/apache/qpid/server/management/ManagedObjectRegistry.java b/java/broker/src/org/apache/qpid/server/management/ManagedObjectRegistry.java deleted file mode 100644 index 32298f05e3..0000000000 --- a/java/broker/src/org/apache/qpid/server/management/ManagedObjectRegistry.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.management; - -import javax.management.JMException; - -/** - * Handles the registration (and unregistration and so on) of managed objects. - * - * Managed objects are responsible for exposting attributes, operations and notifications. They will expose - * these outside the JVM therefore it is important not to use implementation objects directly as managed objects. - * Instead, creating inner classes and exposing those is an effective way of exposing internal state in a - * controlled way. - * - * Although we do not explictly use them while targetting Java 5, the enhanced MXBean approach in Java 6 will - * be the obvious choice for managed objects. - * - */ -public interface ManagedObjectRegistry -{ - void registerObject(ManagedObject managedObject) throws JMException; - - void unregisterObject(ManagedObject managedObject) throws JMException; -} diff --git a/java/broker/src/org/apache/qpid/server/management/ManagementConfiguration.java b/java/broker/src/org/apache/qpid/server/management/ManagementConfiguration.java deleted file mode 100644 index 042f626e8b..0000000000 --- a/java/broker/src/org/apache/qpid/server/management/ManagementConfiguration.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.management; - -import org.apache.qpid.configuration.Configured; - -public class ManagementConfiguration -{ - @Configured(path = "management.enabled", - defaultValue = "true") - public boolean enabled; -} diff --git a/java/broker/src/org/apache/qpid/server/management/NoopManagedObjectRegistry.java b/java/broker/src/org/apache/qpid/server/management/NoopManagedObjectRegistry.java deleted file mode 100644 index 121c992c4f..0000000000 --- a/java/broker/src/org/apache/qpid/server/management/NoopManagedObjectRegistry.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.management; - -import org.apache.log4j.Logger; - -import javax.management.JMException; - -/** - * This managed object registry does not actually register MBeans. This can be used in tests when management is - * not required or when management has been disabled. - * - */ -public class NoopManagedObjectRegistry implements ManagedObjectRegistry -{ - private static final Logger _log = Logger.getLogger(NoopManagedObjectRegistry.class); - - public NoopManagedObjectRegistry() - { - _log.info("Management is disabled"); - } - - public void registerObject(ManagedObject managedObject) throws JMException - { - } - - public void unregisterObject(ManagedObject managedObject) throws JMException - { - } -} diff --git a/java/broker/src/org/apache/qpid/server/protocol/AMQMethodEvent.java b/java/broker/src/org/apache/qpid/server/protocol/AMQMethodEvent.java deleted file mode 100644 index 3d12828900..0000000000 --- a/java/broker/src/org/apache/qpid/server/protocol/AMQMethodEvent.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.protocol; - -import org.apache.qpid.framing.AMQMethodBody; - -/** - * An event that is passed to AMQMethodListeners describing a particular method. - * It supplies the: - *
    • channel id
    • - *
    • protocol method
    • - * to listeners. This means that listeners do not need to be stateful. - * - * In the StateAwareMethodListener, other useful objects such as the protocol session - * are made available. - * - */ -public class AMQMethodEvent -{ - private final M _method; - - private final int _channelId; - - public AMQMethodEvent(int channelId, M method) - { - _channelId = channelId; - _method = method; - } - - public M getMethod() - { - return _method; - } - - public int getChannelId() - { - return _channelId; - } - - public String toString() - { - StringBuilder buf = new StringBuilder("Method event: "); - buf.append("\nChannel id: ").append(_channelId); - buf.append("\nMethod: ").append(_method); - return buf.toString(); - } -} diff --git a/java/broker/src/org/apache/qpid/server/protocol/AMQMethodListener.java b/java/broker/src/org/apache/qpid/server/protocol/AMQMethodListener.java deleted file mode 100644 index d2062d3c17..0000000000 --- a/java/broker/src/org/apache/qpid/server/protocol/AMQMethodListener.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.protocol; - -import org.apache.qpid.AMQException; -import org.apache.qpid.server.queue.QueueRegistry; -import org.apache.qpid.server.exchange.ExchangeRegistry; -import org.apache.qpid.framing.AMQMethodBody; - -/** - * Interface that allows classes to register for interest in protocol method frames. - * - */ -public interface AMQMethodListener -{ - /** - * Invoked when a method frame has been received - * @param evt the event that contains the method and channel - * @param protocolSession the protocol session associated with the event - * @return true if the handler has processed the method frame, false otherwise. Note - * that this does not prohibit the method event being delivered to subsequent listeners - * but can be used to determine if nobody has dealt with an incoming method frame. - * @throws AMQException if an error has occurred. This exception will be delivered - * to all registered listeners using the error() method (see below) allowing them to - * perform cleanup if necessary. - */ - boolean methodReceived(AMQMethodEvent evt, - AMQProtocolSession protocolSession, - QueueRegistry queueRegistry, - ExchangeRegistry exchangeRegistry) throws AMQException; - - /** - * Callback when an error has occurred. Allows listeners to clean up. - * @param e - */ - void error(AMQException e); -} diff --git a/java/broker/src/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java b/java/broker/src/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java deleted file mode 100644 index 966af77d64..0000000000 --- a/java/broker/src/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java +++ /dev/null @@ -1,700 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.protocol; - -import org.apache.log4j.Logger; -import org.apache.mina.common.IdleStatus; -import org.apache.mina.common.IoSession; -import org.apache.mina.transport.vmpipe.VmPipeAddress; -import org.apache.qpid.AMQChannelException; -import org.apache.qpid.AMQException; -import org.apache.qpid.codec.AMQCodecFactory; -import org.apache.qpid.codec.AMQDecoder; -import org.apache.qpid.framing.AMQDataBlock; -import org.apache.qpid.framing.AMQFrame; -import org.apache.qpid.framing.AMQMethodBody; -import org.apache.qpid.framing.ConnectionStartBody; -import org.apache.qpid.framing.ContentBody; -import org.apache.qpid.framing.ContentHeaderBody; -import org.apache.qpid.framing.HeartbeatBody; -import org.apache.qpid.framing.ProtocolInitiation; -import org.apache.qpid.framing.ProtocolVersionList; -import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.server.RequiredDeliveryException; -import org.apache.qpid.server.exchange.ExchangeRegistry; -import org.apache.qpid.server.management.AMQManagedObject; -import org.apache.qpid.server.management.MBeanConstructor; -import org.apache.qpid.server.management.MBeanDescription; -import org.apache.qpid.server.management.Managable; -import org.apache.qpid.server.management.ManagedObject; -import org.apache.qpid.server.queue.QueueRegistry; -import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.state.AMQStateManager; - -import javax.management.JMException; -import javax.management.MBeanException; -import javax.management.MBeanNotificationInfo; -import javax.management.NotCompliantMBeanException; -import javax.management.Notification; -import javax.management.monitor.MonitorNotification; -import javax.management.openmbean.CompositeData; -import javax.management.openmbean.CompositeDataSupport; -import javax.management.openmbean.CompositeType; -import javax.management.openmbean.OpenDataException; -import javax.management.openmbean.OpenType; -import javax.management.openmbean.SimpleType; -import javax.management.openmbean.TabularData; -import javax.management.openmbean.TabularDataSupport; -import javax.management.openmbean.TabularType; -import javax.security.sasl.SaslServer; -import java.net.InetSocketAddress; -import java.net.SocketAddress; -import java.util.Date; -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.CopyOnWriteArraySet; - -public class AMQMinaProtocolSession implements AMQProtocolSession, - ProtocolVersionList, - Managable -{ - private static final Logger _logger = Logger.getLogger(AMQProtocolSession.class); - - private final IoSession _minaProtocolSession; - - private String _contextKey; - - private final Map _channelMap = new HashMap(); - - private final CopyOnWriteArraySet _frameListeners = new CopyOnWriteArraySet(); - - private final AMQStateManager _stateManager; - - private final QueueRegistry _queueRegistry; - - private final ExchangeRegistry _exchangeRegistry; - - private AMQCodecFactory _codecFactory; - - private ManagedAMQProtocolSession _managedObject; - - private SaslServer _saslServer; - - private Object _lastReceived; - - private Object _lastSent; - - private boolean _closed; - - private long _maxNoOfChannels = 1000; - - /* AMQP Version for this session */ - - private byte _major; - private byte _minor; - - public ManagedObject getManagedObject() - { - return _managedObject; - } - - /** - * This class implements the management interface (is an MBean). In order to - * make more attributes, operations and notifications available over JMX simply - * augment the ManagedConnection interface and add the appropriate implementation here. - */ - @MBeanDescription("Management Bean for an AMQ Broker Connection") - private final class ManagedAMQProtocolSession extends AMQManagedObject - implements ManagedConnection - { - private String _name = null; - /** - * Represents the channel attributes sent with channel data. - */ - private String[] _channelAtttibuteNames = { "ChannelId", - "Transactional", - "DefaultQueue", - "UnacknowledgedMessageCount"}; - private String[] _channelAttributeDescriptions = { "Channel Identifier", - "is Channel Transactional?", - "Default Queue Name", - "Unacknowledged Message Count"}; - private OpenType[] _channelAttributeTypes = { SimpleType.INTEGER, - SimpleType.BOOLEAN, - SimpleType.STRING, - SimpleType.INTEGER}; - - private String[] _indexNames = { "ChannelId" }; //Channels in the list will be indexed according to channelId. - private CompositeType _channelType = null; // represents the data type for channel data - private TabularType _channelsType = null; // Datatype for list of channelsType - private TabularDataSupport _channelsList = null; - - @MBeanConstructor("Creates an MBean exposing an AMQ Broker Connection") - public ManagedAMQProtocolSession() throws NotCompliantMBeanException - { - super(ManagedConnection.class, ManagedConnection.TYPE); - init(); - } - - /** - * initialises the CompositeTypes and TabularType attributes. - */ - private void init() - { - String remote = getRemoteAddress(); - remote = "anonymous".equals(remote) ? remote + hashCode() : remote; - _name = jmxEncode(new StringBuffer(remote), 0).toString(); - - try - { - _channelType = new CompositeType("channel", - "Channel Details", - _channelAtttibuteNames, - _channelAttributeDescriptions, - _channelAttributeTypes); - - _channelsType = new TabularType("channelsType", - "List of available channels", - _channelType, - _indexNames); - } - catch(OpenDataException ex) - { - // It should never occur. - _logger.error("OpenDataTypes could not be created.", ex); - throw new RuntimeException(ex); - } - } - - public Date getLastIoTime() - { - return new Date(_minaProtocolSession.getLastIoTime()); - } - - public String getRemoteAddress() - { - return _minaProtocolSession.getRemoteAddress().toString(); - } - - public Long getWrittenBytes() - { - return _minaProtocolSession.getWrittenBytes(); - } - - public Long getReadBytes() - { - return _minaProtocolSession.getReadBytes(); - } - - public Long getMaximumNumberOfAllowedChannels() - { - return _maxNoOfChannels; - } - - public void setMaximumNumberOfAllowedChannels(Long value) - { - _maxNoOfChannels = value; - } - - public String getObjectInstanceName() - { - return _name; - } - - public void commitTransactions(int channelId) throws JMException - { - try - { - AMQChannel channel = _channelMap.get(channelId); - if (channel == null) - { - throw new JMException("The channel (channel Id = " + channelId + ") does not exist"); - } - if (channel.isTransactional()) - { - channel.commit(); - } - } - catch(AMQException ex) - { - throw new MBeanException(ex, ex.toString()); - } - } - - public void rollbackTransactions(int channelId) throws JMException - { - try - { - AMQChannel channel = _channelMap.get(channelId); - if (channel == null) - { - throw new JMException("The channel (channel Id = " + channelId + ") does not exist"); - } - if (channel.isTransactional()) - { - channel.rollback(); - } - } - catch(AMQException ex) - { - throw new MBeanException(ex, ex.toString()); - } - } - - /** - * Creates the list of channels in tabular form from the _channelMap. - * @return list of channels in tabular form. - * @throws OpenDataException - */ - public TabularData getChannels() throws OpenDataException - { - _channelsList = new TabularDataSupport(_channelsType); - - for (Map.Entry entry : _channelMap.entrySet()) - { - AMQChannel channel = entry.getValue(); - Object[] itemValues = {channel.getChannelId(), - channel.isTransactional(), - (channel.getDefaultQueue() != null) ? channel.getDefaultQueue().getName() : null, - channel.getUnacknowledgedMessageMap().size()}; - - CompositeData channelData = new CompositeDataSupport(_channelType, - _channelAtttibuteNames, - itemValues); - - _channelsList.put(channelData); - } - - return _channelsList; - } - - public void closeChannel(int id) - throws Exception - { - try - { - AMQMinaProtocolSession.this.closeChannel(id); - } - catch (AMQException ex) - { - throw new Exception(ex.toString()); - } - } - - public void closeConnection() - throws Exception - { - try - { - AMQMinaProtocolSession.this.closeSession(); - } - catch (AMQException ex) - { - throw new Exception(ex.toString()); - } - } - - @Override - public MBeanNotificationInfo[] getNotificationInfo() - { - String[] notificationTypes = new String[] - {MonitorNotification.THRESHOLD_VALUE_EXCEEDED}; - String name = MonitorNotification.class.getName(); - String description = "An attribute of this MBean has reached threshold value"; - MBeanNotificationInfo info1 = new MBeanNotificationInfo(notificationTypes, - name, - description); - - return new MBeanNotificationInfo[] {info1}; - } - - private void checkForNotification() - { - int channelsCount = _channelMap.size(); - if (channelsCount >= getMaximumNumberOfAllowedChannels()) - { - Notification n = new Notification( - MonitorNotification.THRESHOLD_VALUE_EXCEEDED, - this, - ++_notificationSequenceNumber, - System.currentTimeMillis(), - "ChannelsCount = " + channelsCount + ", ChannelsCount has reached the threshold value"); - - _broadcaster.sendNotification(n); - } - } - - } // End of MBean class - - public AMQMinaProtocolSession(IoSession session, QueueRegistry queueRegistry, ExchangeRegistry exchangeRegistry, - AMQCodecFactory codecFactory) - throws AMQException - { - this(session, queueRegistry, exchangeRegistry, codecFactory, new AMQStateManager()); - } - - public AMQMinaProtocolSession(IoSession session, QueueRegistry queueRegistry, ExchangeRegistry exchangeRegistry, - AMQCodecFactory codecFactory, AMQStateManager stateManager) - throws AMQException - { - _stateManager = stateManager; - _minaProtocolSession = session; - session.setAttachment(this); - _frameListeners.add(_stateManager); - _queueRegistry = queueRegistry; - _exchangeRegistry = exchangeRegistry; - _codecFactory = codecFactory; - _managedObject = createMBean(); - _managedObject.register(); - } - - private ManagedAMQProtocolSession createMBean() throws AMQException - { - try - { - return new ManagedAMQProtocolSession(); - } - catch(NotCompliantMBeanException ex) - { - _logger.error("AMQProtocolSession MBean creation has failed.", ex); - throw new AMQException("AMQProtocolSession MBean creation has failed.", ex); - } - } - - public static AMQProtocolSession getAMQProtocolSession(IoSession minaProtocolSession) - { - return (AMQProtocolSession) minaProtocolSession.getAttachment(); - } - - public void dataBlockReceived(AMQDataBlock message) - throws Exception - { - _lastReceived = message; - if (message instanceof ProtocolInitiation) - { - ProtocolInitiation pi = (ProtocolInitiation) message; - // this ensures the codec never checks for a PI message again - ((AMQDecoder)_codecFactory.getDecoder()).setExpectProtocolInitiation(false); - try { - pi.checkVersion(this); // Fails if not correct - // This sets the protocol version (and hence framing classes) for this session. - _major = pi.protocolMajor; - _minor = pi.protocolMinor; - String mechanisms = ApplicationRegistry.getInstance().getAuthenticationManager().getMechanisms(); - String locales = "en_US"; - AMQFrame response = ConnectionStartBody.createAMQFrame((short)0, pi.protocolMajor, pi.protocolMinor, null, - mechanisms.getBytes(), locales.getBytes()); - _minaProtocolSession.write(response); - } catch (AMQException e) { - _logger.error("Received incorrect protocol initiation", e); - /* Find last protocol version in protocol version list. Make sure last protocol version - listed in the build file (build-module.xml) is the latest version which will be used - here. */ - int i = pv.length - 1; - _minaProtocolSession.write(new ProtocolInitiation(pv[i][PROTOCOL_MAJOR], pv[i][PROTOCOL_MINOR])); - // TODO: Close connection (but how to wait until message is sent?) - } - } - else - { - AMQFrame frame = (AMQFrame) message; - - if (frame.bodyFrame instanceof AMQMethodBody) - { - methodFrameReceived(frame); - } - else - { - try - { - contentFrameReceived(frame); - } - catch (RequiredDeliveryException e) - { - //need to return the message: - _logger.info("Returning message to " + this + " channel " + frame.channel - + ": " + e.getMessage()); - writeFrame(e.getReturnMessage(frame.channel)); - } - } - } - } - - private void methodFrameReceived(AMQFrame frame) - { - if (_logger.isDebugEnabled()) - { - _logger.debug("Method frame received: " + frame); - } - final AMQMethodEvent evt = new AMQMethodEvent(frame.channel, - (AMQMethodBody)frame.bodyFrame); - try - { - boolean wasAnyoneInterested = false; - for (AMQMethodListener listener : _frameListeners) - { - wasAnyoneInterested = listener.methodReceived(evt, this, _queueRegistry, _exchangeRegistry) || - wasAnyoneInterested; - } - if (!wasAnyoneInterested) - { - throw new AMQException("AMQMethodEvent " + evt + " was not processed by any listener."); - } - } - catch (AMQChannelException e) - { - _logger.error("Closing channel due to: " + e.getMessage()); - writeFrame(e.getCloseFrame(frame.channel)); - } - catch (AMQException e) - { - for (AMQMethodListener listener : _frameListeners) - { - listener.error(e); - } - _minaProtocolSession.close(); - } - } - - private void contentFrameReceived(AMQFrame frame) throws AMQException - { - if (frame.bodyFrame instanceof ContentHeaderBody) - { - contentHeaderReceived(frame); - } - else if (frame.bodyFrame instanceof ContentBody) - { - contentBodyReceived(frame); - } - else if (frame.bodyFrame instanceof HeartbeatBody) - { - _logger.debug("Received heartbeat from client"); - } - else - { - _logger.warn("Unrecognised frame " + frame.getClass().getName()); - } - } - - private void contentHeaderReceived(AMQFrame frame) throws AMQException - { - if (_logger.isDebugEnabled()) - { - _logger.debug("Content header frame received: " + frame); - } - getChannel(frame.channel).publishContentHeader((ContentHeaderBody)frame.bodyFrame); - } - - private void contentBodyReceived(AMQFrame frame) throws AMQException - { - if (_logger.isDebugEnabled()) - { - _logger.debug("Content body frame received: " + frame); - } - getChannel(frame.channel).publishContentBody((ContentBody)frame.bodyFrame); - } - - /** - * Convenience method that writes a frame to the protocol session. Equivalent - * to calling getProtocolSession().write(). - * - * @param frame the frame to write - */ - public void writeFrame(AMQDataBlock frame) - { - _lastSent = frame; - _minaProtocolSession.write(frame); - } - - public String getContextKey() - { - return _contextKey; - } - - public void setContextKey(String contextKey) - { - _contextKey = contextKey; - } - - public AMQChannel getChannel(int channelId) throws AMQException - { - return _channelMap.get(channelId); - } - - public void addChannel(AMQChannel channel) - { - _channelMap.put(channel.getChannelId(), channel); - _managedObject.checkForNotification(); - } - - /** - * Close a specific channel. This will remove any resources used by the channel, including: - *
      • any queue subscriptions (this may in turn remove queues if they are auto delete
      • - *
      - * @param channelId id of the channel to close - * @throws AMQException if an error occurs closing the channel - * @throws IllegalArgumentException if the channel id is not valid - */ - public void closeChannel(int channelId) throws AMQException - { - final AMQChannel channel = _channelMap.get(channelId); - if (channel == null) - { - throw new IllegalArgumentException("Unknown channel id"); - } - else - { - try - { - channel.close(this); - } - finally - { - _channelMap.remove(channelId); - } - } - } - - /** - * In our current implementation this is used by the clustering code. - * @param channelId - */ - public void removeChannel(int channelId) - { - _channelMap.remove(channelId); - } - - /** - * Initialise heartbeats on the session. - * @param delay delay in seconds (not ms) - */ - public void initHeartbeats(int delay) - { - if(delay > 0) - { - _minaProtocolSession.setIdleTime(IdleStatus.WRITER_IDLE, delay); - _minaProtocolSession.setIdleTime(IdleStatus.READER_IDLE, HeartbeatConfig.getInstance().getTimeout(delay)); - } - } - - /** - * Closes all channels that were opened by this protocol session. This frees up all resources - * used by the channel. - * @throws AMQException if an error occurs while closing any channel - */ - private void closeAllChannels() throws AMQException - { - for (AMQChannel channel : _channelMap.values()) - { - channel.close(this); - } - } - - /** - * This must be called when the session is _closed in order to free up any resources - * managed by the session. - */ - public void closeSession() throws AMQException - { - if(!_closed) - { - _closed = true; - closeAllChannels(); - if (_managedObject != null) - { - _managedObject.unregister(); - } - } - } - - public String toString() - { - return "AMQProtocolSession(" + _minaProtocolSession.getRemoteAddress() + ")"; - } - - public String dump() - { - return this + " last_sent=" + _lastSent + " last_received=" + _lastReceived; - } - - /** - * @return an object that can be used to identity - */ - public Object getKey() - { - return _minaProtocolSession.getRemoteAddress(); - } - - /** - * Get the fully qualified domain name of the local address to which this session is bound. Since some servers - * may be bound to multiple addresses this could vary depending on the acceptor this session was created from. - * - * @return a String FQDN - */ - public String getLocalFQDN() - { - SocketAddress address = _minaProtocolSession.getLocalAddress(); - // we use the vmpipe address in some tests hence the need for this rather ugly test. The host - // information is used by SASL primary. - if (address instanceof InetSocketAddress) - { - return ((InetSocketAddress)address).getHostName(); - } - else if (address instanceof VmPipeAddress) - { - return "vmpipe:" + ((VmPipeAddress)address).getPort(); - } - else - { - throw new IllegalArgumentException("Unsupported socket address class: " + address); - } - } - - public SaslServer getSaslServer() - { - return _saslServer; - } - - public void setSaslServer(SaslServer saslServer) - { - _saslServer = saslServer; - } - - /** - * Convenience methods for managing AMQP version. - * NOTE: Both major and minor will be set to 0 prior to protocol initiation. - */ - - public byte getAmqpMajor() - { - return _major; - } - - public byte getAmqpMinor() - { - return _minor; - } - - public boolean amqpVersionEquals(byte major, byte minor) - { - return _major == major && _minor == minor; - } -} diff --git a/java/broker/src/org/apache/qpid/server/protocol/AMQPFastProtocolHandler.java b/java/broker/src/org/apache/qpid/server/protocol/AMQPFastProtocolHandler.java deleted file mode 100644 index 18980f440b..0000000000 --- a/java/broker/src/org/apache/qpid/server/protocol/AMQPFastProtocolHandler.java +++ /dev/null @@ -1,230 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.protocol; - -import org.apache.qpid.AMQException; -import org.apache.qpid.codec.AMQCodecFactory; -import org.apache.qpid.framing.*; -import org.apache.qpid.server.exchange.ExchangeRegistry; -import org.apache.qpid.server.queue.QueueRegistry; -import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.registry.IApplicationRegistry; -import org.apache.qpid.server.transport.ConnectorConfiguration; -import org.apache.qpid.ssl.BogusSSLContextFactory; -import org.apache.log4j.Logger; -import org.apache.mina.common.ByteBuffer; -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.ProtocolCodecFilter; -import org.apache.mina.util.SessionUtil; - -import java.io.IOException; - - -/** - * The protocol handler handles "protocol events" for all connections. The state - * associated with an individual connection is accessed through the protocol session. - * - * We delegate all frame (message) processing to the AMQProtocolSession which wraps - * the state for the connection. - * - */ -public class AMQPFastProtocolHandler extends IoHandlerAdapter implements ProtocolVersionList -{ - private static final Logger _logger = Logger.getLogger(AMQPFastProtocolHandler.class); - - /** - * The registry of all queues. This is passed to frame listeners when frame - * events occur. - */ - private final QueueRegistry _queueRegistry; - - /** - * The registry of all exchanges. This is passed to frame listeners when frame - * events occur. - */ - private final ExchangeRegistry _exchangeRegistry; - - private boolean _useSSL; - - public AMQPFastProtocolHandler(Integer applicationRegistryInstance) - { - IApplicationRegistry registry = ApplicationRegistry.getInstance(applicationRegistryInstance); - - _queueRegistry = registry.getQueueRegistry(); - _exchangeRegistry = registry.getExchangeRegistry(); - _logger.debug("AMQPFastProtocolHandler created"); - } - - public AMQPFastProtocolHandler(QueueRegistry queueRegistry, - ExchangeRegistry exchangeRegistry) - { - _queueRegistry = queueRegistry; - _exchangeRegistry = exchangeRegistry; - - _logger.debug("AMQPFastProtocolHandler created"); - } - - protected AMQPFastProtocolHandler(AMQPFastProtocolHandler handler) - { - this(handler._queueRegistry, handler._exchangeRegistry); - } - - public void sessionCreated(IoSession protocolSession) throws Exception - { - SessionUtil.initialize(protocolSession); - final AMQCodecFactory codecFactory = new AMQCodecFactory(true); - - createSession(protocolSession, _queueRegistry, _exchangeRegistry, codecFactory); - _logger.info("Protocol session created"); - - final ProtocolCodecFilter pcf = new ProtocolCodecFilter(codecFactory); - - ConnectorConfiguration connectorConfig = ApplicationRegistry.getInstance(). - getConfiguredObject(ConnectorConfiguration.class); - if (connectorConfig.enableExecutorPool) - { - if (_useSSL) - { - protocolSession.getFilterChain().addAfter("AsynchronousReadFilter", "sslFilter", - new SSLFilter(BogusSSLContextFactory.getInstance(true))); - } - protocolSession.getFilterChain().addBefore("AsynchronousWriteFilter", "protocolFilter", pcf); - } - else - { - protocolSession.getFilterChain().addLast("protocolFilter", pcf); - } - } - - /** - * Separated into its own, protected, method to allow easier reuse - */ - protected void createSession(IoSession session, QueueRegistry queues, ExchangeRegistry exchanges, AMQCodecFactory codec) throws AMQException - { - new AMQMinaProtocolSession(session, queues, exchanges, codec); - } - - public void sessionOpened(IoSession protocolSession) throws Exception - { - _logger.info("Session opened"); - } - - public void sessionClosed(IoSession protocolSession) throws Exception - { - _logger.info("Protocol Session closed"); - final AMQProtocolSession amqProtocolSession = AMQMinaProtocolSession.getAMQProtocolSession(protocolSession); - amqProtocolSession.closeSession(); - } - - public void sessionIdle(IoSession session, IdleStatus status) throws Exception - { - _logger.debug("Protocol Session [" + this + "] idle: " + status); - if(IdleStatus.WRITER_IDLE.equals(status)) - { - //write heartbeat frame: - session.write(HeartbeatBody.FRAME); - } - else if(IdleStatus.READER_IDLE.equals(status)) - { - //failover: - throw new IOException("Timed out while waiting for heartbeat from peer."); - } - - } - - public void exceptionCaught(IoSession protocolSession, Throwable throwable) throws Exception - { - AMQProtocolSession session = AMQMinaProtocolSession.getAMQProtocolSession(protocolSession); - if (throwable instanceof AMQProtocolHeaderException) - { - /* Find last protocol version in protocol version list. Make sure last protocol version - listed in the build file (build-module.xml) is the latest version which will be returned - here. */ - int i = pv.length - 1; - protocolSession.write(new ProtocolInitiation(pv[i][PROTOCOL_MAJOR], pv[i][PROTOCOL_MINOR])); - protocolSession.close(); - _logger.error("Error in protocol initiation " + session + ": " + throwable.getMessage(), throwable); - } - else if(throwable instanceof IOException) - { - _logger.error("IOException caught in" + session + ", session closed implictly: " + throwable, throwable); - } - else - { - protocolSession.write(ConnectionCloseBody.createAMQFrame(0, 200, throwable.getMessage(), 0, 0)); - _logger.error("Exception caught in" + session + ", closing session explictly: " + throwable, throwable); - protocolSession.close(); - } - } - - /** - * Invoked when a message is received on a particular protocol session. Note that a - * protocol session is directly tied to a particular physical connection. - * @param protocolSession the protocol session that received the message - * @param message the message itself (i.e. a decoded frame) - * @throws Exception if the message cannot be processed - */ - public void messageReceived(IoSession protocolSession, Object message) throws Exception - { - final AMQProtocolSession amqProtocolSession = AMQMinaProtocolSession.getAMQProtocolSession(protocolSession); - - if (message instanceof AMQDataBlock) - { - amqProtocolSession.dataBlockReceived((AMQDataBlock) message); - } - else if (message instanceof ByteBuffer) - { - throw new IllegalStateException("Handed undecoded ByteBuffer buf = " + message); - } - else - { - throw new IllegalStateException("Handed unhandled message. message.class = " + message.getClass() + " message = " + message); - } - } - - /** - * Called after a message has been sent out on a particular protocol session - * @param protocolSession the protocol session (i.e. connection) on which this - * message was sent - * @param object the message (frame) that was encoded and sent - * @throws Exception if we want to indicate an error - */ - public void messageSent(IoSession protocolSession, Object object) throws Exception - { - if (_logger.isDebugEnabled()) - { - _logger.debug("Message sent: " + object); - } - } - - public boolean isUseSSL() - { - return _useSSL; - } - - public void setUseSSL(boolean useSSL) - { - _useSSL = useSSL; - } -} diff --git a/java/broker/src/org/apache/qpid/server/protocol/AMQPProtocolProvider.java b/java/broker/src/org/apache/qpid/server/protocol/AMQPProtocolProvider.java deleted file mode 100644 index ff1316f704..0000000000 --- a/java/broker/src/org/apache/qpid/server/protocol/AMQPProtocolProvider.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.protocol; - -import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.registry.IApplicationRegistry; - -/** - * The protocol provide's role is to encapsulate the initialisation of the protocol handler. - * - * The protocol handler (see AMQPFastProtocolHandler class) handles protocol events - * such as connection closing or a frame being received. It can either do this directly - * or pass off to the protocol session in the cases where state information is required to - * deal with the event. - * - */ -public class AMQPProtocolProvider -{ - /** - * Handler for protocol events - */ - private AMQPFastProtocolHandler _handler; - - public AMQPProtocolProvider() - { - IApplicationRegistry registry = ApplicationRegistry.getInstance(); - _handler = new AMQPFastProtocolHandler(registry.getQueueRegistry(), - registry.getExchangeRegistry()); - } - - public AMQPFastProtocolHandler getHandler() - { - return _handler; - } -} diff --git a/java/broker/src/org/apache/qpid/server/protocol/AMQProtocolSession.java b/java/broker/src/org/apache/qpid/server/protocol/AMQProtocolSession.java deleted file mode 100644 index acaf6b0d9b..0000000000 --- a/java/broker/src/org/apache/qpid/server/protocol/AMQProtocolSession.java +++ /dev/null @@ -1,125 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.protocol; - -import org.apache.qpid.framing.AMQDataBlock; -import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.AMQException; - -import javax.security.sasl.SaslServer; - - -public interface AMQProtocolSession -{ - /** - * Called when a protocol data block is received - * @param message the data block that has been received - * @throws Exception if processing the datablock fails - */ - void dataBlockReceived(AMQDataBlock message) throws Exception; - - /** - * Write a datablock, encoding where necessary (e.g. into a sequence of bytes) - * @param frame the frame to be encoded and written - */ - void writeFrame(AMQDataBlock frame); - - /** - * Get the context key associated with this session. Context key is described - * in the AMQ protocol specification (RFC 6). - * @return the context key - */ - String getContextKey(); - - /** - * Set the context key associated with this session. Context key is described - * in the AMQ protocol specification (RFC 6). - * @param contextKey the context key - */ - void setContextKey(String contextKey); - - /** - * Get the channel for this session associated with the specified id. A channel - * id is unique per connection (i.e. per session). - * @param channelId the channel id which must be valid - * @return null if no channel exists, the channel otherwise - */ - AMQChannel getChannel(int channelId) throws AMQException; - - /** - * Associate a channel with this session. - * @param channel the channel to associate with this session. It is an error to - * associate the same channel with more than one session but this is not validated. - */ - void addChannel(AMQChannel channel); - - /** - * Close a specific channel. This will remove any resources used by the channel, including: - *
      • any queue subscriptions (this may in turn remove queues if they are auto delete
      • - *
      - * @param channelId id of the channel to close - * @throws org.apache.qpid.AMQException if an error occurs closing the channel - * @throws IllegalArgumentException if the channel id is not valid - */ - void closeChannel(int channelId) throws AMQException; - - /** - * Remove a channel from the session but do not close it. - * @param channelId - */ - void removeChannel(int channelId); - - /** - * Initialise heartbeats on the session. - * @param delay delay in seconds (not ms) - */ - void initHeartbeats(int delay); - - /** - * This must be called when the session is _closed in order to free up any resources - * managed by the session. - */ - void closeSession() throws AMQException; - - /** - * @return a key that uniquely identifies this session - */ - Object getKey(); - - /** - * Get the fully qualified domain name of the local address to which this session is bound. Since some servers - * may be bound to multiple addresses this could vary depending on the acceptor this session was created from. - * - * @return a String FQDN - */ - String getLocalFQDN(); - - /** - * @return the sasl server that can perform authentication for this session. - */ - SaslServer getSaslServer(); - - /** - * Set the sasl server that is to perform authentication for this session. - * @param saslServer - */ - void setSaslServer(SaslServer saslServer); -} diff --git a/java/broker/src/org/apache/qpid/server/protocol/ExchangeInitialiser.java b/java/broker/src/org/apache/qpid/server/protocol/ExchangeInitialiser.java deleted file mode 100644 index d3ec70456f..0000000000 --- a/java/broker/src/org/apache/qpid/server/protocol/ExchangeInitialiser.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.protocol; - -import org.apache.qpid.AMQException; -import org.apache.qpid.exchange.ExchangeDefaults; -import org.apache.qpid.server.exchange.ExchangeFactory; -import org.apache.qpid.server.exchange.ExchangeRegistry; - -public class ExchangeInitialiser -{ - public void initialise(ExchangeFactory factory, ExchangeRegistry registry) throws AMQException{ - define(registry, factory, ExchangeDefaults.DIRECT_EXCHANGE_NAME, ExchangeDefaults.DIRECT_EXCHANGE_CLASS); - define(registry, factory, ExchangeDefaults.TOPIC_EXCHANGE_NAME, ExchangeDefaults.TOPIC_EXCHANGE_CLASS); - define(registry, factory, ExchangeDefaults.HEADERS_EXCHANGE_NAME, ExchangeDefaults.HEADERS_EXCHANGE_CLASS); - } - - private void define(ExchangeRegistry r, ExchangeFactory f, - String name, String type) throws AMQException - { - r.registerExchange(f.createExchange(name, type, true, false, 0)); - } -} diff --git a/java/broker/src/org/apache/qpid/server/protocol/HeartbeatConfig.java b/java/broker/src/org/apache/qpid/server/protocol/HeartbeatConfig.java deleted file mode 100644 index 310deaaf55..0000000000 --- a/java/broker/src/org/apache/qpid/server/protocol/HeartbeatConfig.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.protocol; - -import org.apache.qpid.configuration.Configured; -import org.apache.qpid.server.registry.ApplicationRegistry; - -public class HeartbeatConfig -{ - @Configured(path = "heartbeat.delay", defaultValue = "5") - public int delay = 5;//in secs - @Configured(path = "heartbeat.timeoutFactor", defaultValue = "2.0") - public double timeoutFactor = 2; - - public double getTimeoutFactor() - { - return timeoutFactor; - } - - public void setTimeoutFactor(double timeoutFactor) - { - this.timeoutFactor = timeoutFactor; - } - - public int getDelay() - { - return delay; - } - - public void setDelay(int delay) - { - this.delay = delay; - } - - int getTimeout(int writeDelay) - { - return (int) (timeoutFactor * writeDelay); - } - - public static HeartbeatConfig getInstance() - { - return ApplicationRegistry.getInstance().getConfiguredObject(HeartbeatConfig.class); - } - - public String toString() - { - return "HeartBeatConfig{delay = " + delay + " timeoutFactor = " + timeoutFactor + "}"; - } -} diff --git a/java/broker/src/org/apache/qpid/server/protocol/ManagedConnection.java b/java/broker/src/org/apache/qpid/server/protocol/ManagedConnection.java deleted file mode 100644 index 889acd0142..0000000000 --- a/java/broker/src/org/apache/qpid/server/protocol/ManagedConnection.java +++ /dev/null @@ -1,141 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ - -package org.apache.qpid.server.protocol; - -import org.apache.qpid.server.management.MBeanOperationParameter; -import org.apache.qpid.server.management.MBeanAttribute; -import org.apache.qpid.server.management.MBeanOperation; - -import javax.management.openmbean.TabularData; -import javax.management.JMException; -import javax.management.MBeanOperationInfo; -import java.util.Date; -import java.io.IOException; - -/** - * The management interface exposed to allow management of Connections. - * @author Bhupendra Bhardwaj - * @version 0.1 - */ -public interface ManagedConnection -{ - static final String TYPE = "Connection"; - - /** - * channel details of all the channels opened for this connection. - * @return general channel details - * @throws IOException - * @throws JMException - */ - @MBeanAttribute(name="Channels", - description="channel details of all the channels opened for this connection") - TabularData getChannels() throws IOException, JMException; - - /** - * Tells the last time, the IO operation was done. - * @return last IO time. - */ - @MBeanAttribute(name="LastIOTime", - description="The last time, the IO operation was done") - Date getLastIoTime(); - - /** - * Tells the remote address of this connection. - * @return remote address - */ - @MBeanAttribute(name="RemoteAddress", - description="The remote address of this connection") - String getRemoteAddress(); - - /** - * Tells the total number of bytes written till now. - * @return number of bytes written. - */ - @MBeanAttribute(name="WrittenBytes", - description="The total number of bytes written till now") - Long getWrittenBytes(); - - /** - * Tells the total number of bytes read till now. - * @return number of bytes read. - */ - @MBeanAttribute(name="ReadBytes", - description="The total number of bytes read till now") - Long getReadBytes(); - - /** - * Tells the maximum number of channels that can be opened using - * this connection. This is useful in setting notifications or - * taking required action is there are more channels being created. - * @return maximum number of channels allowed to be created. - */ - Long getMaximumNumberOfAllowedChannels(); - - /** - * Sets the maximum number of channels allowed to be created using - * this connection. - * @param value - */ - @MBeanAttribute(name="MaximumNumberOfAllowedChannels", - description="The maximum number of channels that can be opened using this connection") - void setMaximumNumberOfAllowedChannels(Long value); - - //********** Operations *****************// - - /** - * Closes all the related channels and unregisters this connection from managed objects. - */ - @MBeanOperation(name="closeConnection", - description="Closes this connection and all related channels", - impact= MBeanOperationInfo.ACTION) - void closeConnection() throws Exception; - - /** - * Unsubscribes the consumers and unregisters the channel from managed objects. - */ - @MBeanOperation(name="closeChannel", - description="Closes the channel with given channeld and" + - "connected consumers will be unsubscribed", - impact= MBeanOperationInfo.ACTION) - void closeChannel(@MBeanOperationParameter(name="channel Id", description="channel Id")int channelId) - throws Exception; - - /** - * Commits the transactions if the channel is transactional. - * @param channelId - * @throws JMException - */ - @MBeanOperation(name="commitTransaction", - description="Commits the transactions for given channelID, if the channel is transactional", - impact= MBeanOperationInfo.ACTION) - void commitTransactions(@MBeanOperationParameter(name="channel Id", description="channel Id")int channelId) throws JMException; - - /** - * Rollsback the transactions if the channel is transactional. - * @param channelId - * @throws JMException - */ - @MBeanOperation(name="rollbackTransactions", - description="Rollsback the transactions for given channelId, if the channel is transactional", - impact= MBeanOperationInfo.ACTION) - void rollbackTransactions(@MBeanOperationParameter(name="channel Id", description="channel Id")int channelId) throws JMException; -} diff --git a/java/broker/src/org/apache/qpid/server/queue/AMQMessage.java b/java/broker/src/org/apache/qpid/server/queue/AMQMessage.java deleted file mode 100644 index 8b6db5b53f..0000000000 --- a/java/broker/src/org/apache/qpid/server/queue/AMQMessage.java +++ /dev/null @@ -1,368 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - -import org.apache.mina.common.ByteBuffer; -import org.apache.qpid.framing.*; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.store.MessageStore; -import org.apache.qpid.server.txn.TxnBuffer; -import org.apache.qpid.AMQException; - -import java.util.ArrayList; -import java.util.List; -import java.util.LinkedList; -import java.util.Set; -import java.util.HashSet; -import java.util.concurrent.atomic.AtomicInteger; - -/** - * Combines the information that make up a deliverable message into a more manageable form. - */ -public class AMQMessage -{ - private final Set _tokens = new HashSet(); - - private AMQProtocolSession _publisher; - - private final BasicPublishBody _publishBody; - - private ContentHeaderBody _contentHeaderBody; - - private List _contentBodies; - - private boolean _redelivered; - - private final long _messageId; - - private final AtomicInteger _referenceCount = new AtomicInteger(1); - - /** - * Keeps a track of how many bytes we have received in body frames - */ - private long _bodyLengthReceived = 0; - - /** - * The message store in which this message is contained. - */ - private transient final MessageStore _store; - - /** - * For non transactional publishes, a message can be stored as - * soon as it is complete. For transactional messages it doesnt - * need to be stored until the transaction is committed. - */ - private boolean _storeWhenComplete; - - /** - * TxnBuffer for transactionally published messages - */ - private TxnBuffer _txnBuffer; - - /** - * Flag to indicate whether message has been delivered to a - * consumer. Used in implementing return functionality for - * messages published with the 'immediate' flag. - */ - private boolean _deliveredToConsumer; - - - public AMQMessage(MessageStore messageStore, BasicPublishBody publishBody) - { - this(messageStore, publishBody, true); - } - - public AMQMessage(MessageStore messageStore, BasicPublishBody publishBody, boolean storeWhenComplete) - { - _messageId = messageStore.getNewMessageId(); - _publishBody = publishBody; - _store = messageStore; - _contentBodies = new LinkedList(); - _storeWhenComplete = storeWhenComplete; - } - - public AMQMessage(MessageStore store, long messageId, BasicPublishBody publishBody, - ContentHeaderBody contentHeaderBody, List contentBodies) - throws AMQException - - { - _publishBody = publishBody; - _contentHeaderBody = contentHeaderBody; - _contentBodies = contentBodies; - _messageId = messageId; - _store = store; - storeMessage(); - } - - public AMQMessage(MessageStore store, BasicPublishBody publishBody, - ContentHeaderBody contentHeaderBody, List contentBodies) - throws AMQException - { - this(store, store.getNewMessageId(), publishBody, contentHeaderBody, contentBodies); - } - - protected AMQMessage(AMQMessage msg) throws AMQException - { - this(msg._store, msg._messageId, msg._publishBody, msg._contentHeaderBody, msg._contentBodies); - } - - public void storeMessage() throws AMQException - { - if (isPersistent()) - { - _store.put(this); - } - } - - public CompositeAMQDataBlock getDataBlock(ByteBuffer encodedDeliverBody, int channel) - { - AMQFrame[] allFrames = new AMQFrame[1 + _contentBodies.size()]; - - allFrames[0] = ContentHeaderBody.createAMQFrame(channel, _contentHeaderBody); - for (int i = 1; i < allFrames.length; i++) - { - allFrames[i] = ContentBody.createAMQFrame(channel, _contentBodies.get(i - 1)); - } - return new CompositeAMQDataBlock(encodedDeliverBody, allFrames); - } - - public CompositeAMQDataBlock getDataBlock(int channel, String consumerTag, long deliveryTag) - { - AMQFrame[] allFrames = new AMQFrame[2 + _contentBodies.size()]; - - allFrames[0] = BasicDeliverBody.createAMQFrame(channel, consumerTag, deliveryTag, _redelivered, - getExchangeName(), getRoutingKey()); - allFrames[1] = ContentHeaderBody.createAMQFrame(channel, _contentHeaderBody); - for (int i = 2; i < allFrames.length; i++) - { - allFrames[i] = ContentBody.createAMQFrame(channel, _contentBodies.get(i - 2)); - } - return new CompositeAMQDataBlock(allFrames); - } - - public List getPayload() - { - List payload = new ArrayList(2 + _contentBodies.size()); - payload.add(_publishBody); - payload.add(_contentHeaderBody); - payload.addAll(_contentBodies); - return payload; - } - - public BasicPublishBody getPublishBody() - { - return _publishBody; - } - - public ContentHeaderBody getContentHeaderBody() - { - return _contentHeaderBody; - } - - public void setContentHeaderBody(ContentHeaderBody contentHeaderBody) throws AMQException - { - _contentHeaderBody = contentHeaderBody; - if (_storeWhenComplete && isAllContentReceived()) - { - storeMessage(); - } - } - - public List getContentBodies() - { - return _contentBodies; - } - - public void setContentBodies(List contentBodies) - { - _contentBodies = contentBodies; - } - - public void addContentBodyFrame(ContentBody contentBody) throws AMQException - { - _contentBodies.add(contentBody); - _bodyLengthReceived += contentBody.getSize(); - if (_storeWhenComplete && isAllContentReceived()) - { - storeMessage(); - } - } - - public boolean isAllContentReceived() - { - return _bodyLengthReceived == _contentHeaderBody.bodySize; - } - - public boolean isRedelivered() - { - return _redelivered; - } - - String getExchangeName() - { - return _publishBody.exchange; - } - - String getRoutingKey() - { - return _publishBody.routingKey; - } - - boolean isImmediate() - { - return _publishBody.immediate; - } - - NoConsumersException getNoConsumersException(String queue) - { - return new NoConsumersException(queue, _publishBody, _contentHeaderBody, _contentBodies); - } - - void setRedelivered(boolean redelivered) - { - _redelivered = redelivered; - } - - public long getMessageId() - { - return _messageId; - } - - /** - * Threadsafe. Increment the reference count on the message. - */ - public void incrementReference() - { - _referenceCount.incrementAndGet(); - } - - /** - * Threadsafe. This will decrement the reference count and when it reaches zero will remove the message from the - * message store. - */ - public void decrementReference() throws MessageCleanupException - { - // note that the operation of decrementing the reference count and then removing the message does not - // have to be atomic since the ref count starts at 1 and the exchange itself decrements that after - // the message has been passed to all queues. i.e. we are - // not relying on the all the increments having taken place before the delivery manager decrements. - if (_referenceCount.decrementAndGet() == 0) - { - try - { - _store.removeMessage(_messageId); - } - catch(AMQException e) - { - //to maintain consistency, we revert the count - incrementReference(); - throw new MessageCleanupException(_messageId, e); - } - } - } - - public void setPublisher(AMQProtocolSession publisher) - { - _publisher = publisher; - } - - public AMQProtocolSession getPublisher() - { - return _publisher; - } - - public boolean checkToken(Object token) - { - if(_tokens.contains(token)) - { - return true; - } - else - { - _tokens.add(token); - return false; - } - } - - public void enqueue(AMQQueue queue) throws AMQException - { - //if the message is not persistent or the queue is not durable - //we will not need to recover the association and so do not - //need to record it - if(isPersistent() && queue.isDurable()) - { - _store.enqueueMessage(queue.getName(), _messageId); - } - } - - public void dequeue(AMQQueue queue) throws AMQException - { - //only record associations where both queue and message will survive - //a restart, so only need to remove association if this is the case - if(isPersistent() && queue.isDurable()) - { - _store.dequeueMessage(queue.getName(), _messageId); - } - } - - public boolean isPersistent() throws AMQException - { - if(_contentHeaderBody == null) - { - throw new AMQException("Cannot determine delivery mode of message. Content header not found."); - } - - //todo remove literal values to a constant file such as AMQConstants in common - return _contentHeaderBody.properties instanceof BasicContentHeaderProperties - &&((BasicContentHeaderProperties) _contentHeaderBody.properties).getDeliveryMode() == 2; - } - - public void setTxnBuffer(TxnBuffer buffer) - { - _txnBuffer = buffer; - } - - public TxnBuffer getTxnBuffer() - { - return _txnBuffer; - } - - /** - * Called to enforce the 'immediate' flag. - * @throws NoConsumersException if the message is marked for - * immediate delivery but has not been marked as delivered to a - * consumer - */ - public void checkDeliveredToConsumer() throws NoConsumersException{ - if(isImmediate() && !_deliveredToConsumer) - { - throw new NoConsumersException(_publishBody, _contentHeaderBody, _contentBodies); - } - } - - /** - * Called when this message is delivered to a consumer. (used to - * implement the 'immediate' flag functionality). - */ - public void setDeliveredToConsumer(){ - _deliveredToConsumer = true; - } -} diff --git a/java/broker/src/org/apache/qpid/server/queue/AMQQueue.java b/java/broker/src/org/apache/qpid/server/queue/AMQQueue.java deleted file mode 100644 index f2f46d43dd..0000000000 --- a/java/broker/src/org/apache/qpid/server/queue/AMQQueue.java +++ /dev/null @@ -1,867 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - -import org.apache.log4j.Logger; -import org.apache.mina.common.ByteBuffer; -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.BasicContentHeaderProperties; -import org.apache.qpid.framing.ContentBody; -import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.server.management.AMQManagedObject; -import org.apache.qpid.server.management.MBeanConstructor; -import org.apache.qpid.server.management.MBeanDescription; -import org.apache.qpid.server.management.Managable; -import org.apache.qpid.server.management.ManagedObject; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.txn.TxnBuffer; -import org.apache.qpid.server.txn.TxnOp; - -import javax.management.JMException; -import javax.management.MBeanException; -import javax.management.MBeanNotificationInfo; -import javax.management.NotCompliantMBeanException; -import javax.management.Notification; -import javax.management.monitor.MonitorNotification; -import javax.management.openmbean.*; -import java.text.MessageFormat; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.Executor; - -/** - * This is an AMQ Queue, and should not be confused with a JMS queue or any other abstraction like - * that. It is described fully in RFC 006. - */ -public class AMQQueue implements Managable -{ - private static final Logger _logger = Logger.getLogger(AMQQueue.class); - - private final String _name; - - /** - * null means shared - */ - private final String _owner; - - private final boolean _durable; - - /** - * If true, this queue is deleted when the last subscriber is removed - */ - private final boolean _autoDelete; - - /** - * Holds subscribers to the queue. - */ - private final SubscriptionSet _subscribers; - - private final SubscriptionFactory _subscriptionFactory; - - /** - * Manages message delivery. - */ - private final DeliveryManager _deliveryMgr; - - /** - * The queue registry with which this queue is registered. - */ - private final QueueRegistry _queueRegistry; - - /** - * Used to track bindings to exchanges so that on deletion they can easily - * be cancelled. - */ - private final ExchangeBindings _bindings = new ExchangeBindings(this); - - /** - * Executor on which asynchronous delivery will be carriedout where required - */ - private final Executor _asyncDelivery; - - private final AMQQueueMBean _managedObject; - - /** - * max allowed size of a single message(in KBytes). - */ - private long _maxAllowedMessageSize = 10000; // 10 MB - - /** - * max allowed number of messages on a queue. - */ - private Integer _maxAllowedMessageCount = 10000; - - /** - * max allowed size in KBytes for all the messages combined together in a queue. - */ - private long _queueDepth = 10000000; // 10 GB - - /** - * total messages received by the queue since startup. - */ - private long _totalMessagesReceived = 0; - - /** - * MBean class for AMQQueue. It implements all the management features exposed - * for an AMQQueue. - */ - @MBeanDescription("Management Interface for AMQQueue") - private final class AMQQueueMBean extends AMQManagedObject implements ManagedQueue - { - private String _queueName = null; - - // AMQ message attribute names - private String[] _msgAttributeNames = {"MessageId", - "Header", - "Size", - "Redelivered" - }; - // AMQ Message attribute descriptions. - private String[] _msgAttributeDescriptions = {"Message Id", - "Header", - "Message size in bytes", - "Redelivered" - }; - - private OpenType[] _msgAttributeTypes = new OpenType[4]; // AMQ message attribute types. - private String[] _msgAttributeIndex = {"MessageId"}; // Messages will be indexed according to the messageId. - private CompositeType _messageDataType = null; // Composite type for representing AMQ Message data. - private TabularType _messagelistDataType = null; // Datatype for representing AMQ messages list. - - - private CompositeType _msgContentType = null; // For message content - private String[] _msgContentAttributes = {"MessageId", - "MimeType", - "Encoding", - "Content" - }; - private String[] _msgContentDescriptions = {"Message Id", - "MimeType", - "Encoding", - "Message content" - }; - private OpenType[] _msgContentAttributeTypes = new OpenType[4]; - - - @MBeanConstructor("Creates an MBean exposing an AMQQueue.") - public AMQQueueMBean() throws NotCompliantMBeanException - { - super(ManagedQueue.class, ManagedQueue.TYPE); - init(); - } - - private void init() - { - _queueName = jmxEncode(new StringBuffer(_name), 0).toString(); - try - { - _msgContentAttributeTypes[0] = SimpleType.LONG; // For message id - _msgContentAttributeTypes[1] = SimpleType.STRING; // For MimeType - _msgContentAttributeTypes[2] = SimpleType.STRING; // For Encoding - _msgContentAttributeTypes[3] = new ArrayType(1, SimpleType.BYTE); // For message content - _msgContentType = new CompositeType("MessageContent", - "AMQ Message Content", - _msgContentAttributes, - _msgContentDescriptions, - _msgContentAttributeTypes); - - - _msgAttributeTypes[0] = SimpleType.LONG; // For message id - _msgAttributeTypes[1] = new ArrayType(1, SimpleType.STRING); // For header attributes - _msgAttributeTypes[2] = SimpleType.LONG; // For size - _msgAttributeTypes[3] = SimpleType.BOOLEAN; // For redelivered - - _messageDataType = new CompositeType("Message", - "AMQ Message", - _msgAttributeNames, - _msgAttributeDescriptions, - _msgAttributeTypes); - _messagelistDataType = new TabularType("Messages", - "List of messages", - _messageDataType, - _msgAttributeIndex); - } - catch (OpenDataException ex) - { - _logger.error("OpenDataTypes could not be created.", ex); - throw new RuntimeException(ex); - } - } - - public String getObjectInstanceName() - { - return _queueName; - } - - public String getName() - { - return _name; - } - - public boolean isDurable() - { - return _durable; - } - - public String getOwner() - { - return _owner; - } - - public boolean isAutoDelete() - { - return _autoDelete; - } - - public Integer getMessageCount() - { - return _deliveryMgr.getQueueMessageCount(); - } - - public Long getMaximumMessageSize() - { - return _maxAllowedMessageSize; - } - - public void setMaximumMessageSize(Long value) - { - _maxAllowedMessageSize = value; - } - - public Integer getConsumerCount() - { - return _subscribers.size(); - } - - public Integer getActiveConsumerCount() - { - return _subscribers.getWeight(); - } - - public Long getReceivedMessageCount() - { - return _totalMessagesReceived; - } - - public Integer getMaximumMessageCount() - { - return _maxAllowedMessageCount; - } - - public void setMaximumMessageCount(Integer value) - { - _maxAllowedMessageCount = value; - } - - public Long getQueueDepth() - { - return _queueDepth; - } - - // Sets the queue depth, the max queue size - public void setQueueDepth(Long value) - { - _queueDepth = value; - } - - // Returns the size of messages in the queue - public Long getQueueSize() - { - List list = _deliveryMgr.getMessages(); - if (list.size() == 0) - { - return 0l; - } - - long queueSize = 0; - for (AMQMessage message : list) - { - queueSize = queueSize + getMessageSize(message); - } - return new Long(Math.round(queueSize / 100)); - } - - // calculates the size of an AMQMessage - private long getMessageSize(AMQMessage msg) - { - if (msg == null) - { - return 0l; - } - - List cBodies = msg.getContentBodies(); - long messageSize = 0; - for (ContentBody body : cBodies) - { - if (body != null) - { - messageSize = messageSize + body.getSize(); - } - } - return messageSize; - } - - // Checks if there is any notification to be send to the listeners - private void checkForNotification(AMQMessage msg) - { - // Check for message count - Integer msgCount = getMessageCount(); - if (msgCount >= getMaximumMessageCount()) - { - notifyClients("MessageCount = " + msgCount + ", Queue has reached its size limit and is now full."); - } - - // Check for received message size - long messageSize = getMessageSize(msg); - if (messageSize >= getMaximumMessageSize()) - { - notifyClients("MessageSize = " + messageSize + ", Message size (MessageID=" + msg.getMessageId() + - ")is higher than the threshold value"); - } - - // Check for queue size in bytes - long queueSize = getQueueSize(); - if (queueSize >= getQueueDepth()) - { - notifyClients("QueueSize = " + queueSize + ", Queue size has reached the threshold value"); - } - } - - // Send the notification to the listeners - private void notifyClients(String notificationMsg) - { - Notification n = new Notification( - MonitorNotification.THRESHOLD_VALUE_EXCEEDED, - this, - ++_notificationSequenceNumber, - System.currentTimeMillis(), - notificationMsg); - - _broadcaster.sendNotification(n); - } - - public void deleteMessageFromTop() throws JMException - { - try - { - _deliveryMgr.removeAMessageFromTop(); - } - catch (AMQException ex) - { - throw new MBeanException(ex, ex.toString()); - } - } - - public void clearQueue() throws JMException - { - try - { - _deliveryMgr.clearAllMessages(); - } - catch (AMQException ex) - { - throw new MBeanException(ex, ex.toString()); - } - } - - public CompositeData viewMessageContent(long msgId) throws JMException - { - List list = _deliveryMgr.getMessages(); - CompositeData messageContent = null; - AMQMessage msg = null; - for (AMQMessage message : list) - { - if (message.getMessageId() == msgId) - { - msg = message; - break; - } - } - - if (msg != null) - { - // get message content - List cBodies = msg.getContentBodies(); - List msgContent = new ArrayList(); - for (ContentBody body : cBodies) - { - if (body.getSize() != 0) - { - ByteBuffer slice = body.payload.slice(); - for (int j = 0; j < slice.limit(); j++) - { - msgContent.add(slice.get()); - } - } - } - - // Create header attributes list - BasicContentHeaderProperties headerProperties = (BasicContentHeaderProperties)msg.getContentHeaderBody().properties; - String mimeType = headerProperties.getContentType(); - String encoding = headerProperties.getEncoding() == null ? "" : headerProperties.getEncoding(); - - Object[] itemValues = {msgId, mimeType, encoding, msgContent.toArray(new Byte[0])}; - messageContent = new CompositeDataSupport(_msgContentType, _msgContentAttributes, itemValues); - } - else - { - throw new JMException("AMQMessage with message id = " + msgId + " is not in the " + _queueName ); - } - - return messageContent; - } - - /** - * Returns the messages stored in this queue in tabular form. - * - * @param beginIndex - * @param endIndex - * @return AMQ messages in tabular form. - * @throws JMException - */ - public TabularData viewMessages(int beginIndex, int endIndex) throws JMException - { - if ((beginIndex > endIndex) || (beginIndex < 1)) - { - throw new JMException("FromIndex = " + beginIndex + ", ToIndex = " + endIndex + - "\nFromIndex should be greater than 0 and less than ToIndex"); - } - - List list = _deliveryMgr.getMessages(); - TabularDataSupport _messageList = new TabularDataSupport(_messagelistDataType); - - if (beginIndex > list.size()) - { - return _messageList; - } - endIndex = endIndex < list.size() ? endIndex : list.size(); - - for (int i = beginIndex; i <= endIndex; i++) - { - AMQMessage msg = list.get(i - 1); - long size = 0; - // get message content - List cBodies = msg.getContentBodies(); - for (ContentBody body : cBodies) - { - size = size + body.getSize(); - } - - // Create header attributes list - BasicContentHeaderProperties headerProperties = (BasicContentHeaderProperties)msg.getContentHeaderBody().properties; - List headerAttribsList = new ArrayList(); - headerAttribsList.add("App Id=" + headerProperties.getAppId()); - headerAttribsList.add("MimeType=" + headerProperties.getContentType()); - headerAttribsList.add("Correlation Id=" + headerProperties.getCorrelationId()); - headerAttribsList.add("Encoding=" + headerProperties.getEncoding()); - headerAttribsList.add(headerProperties.toString()); - - Object[] itemValues = {msg.getMessageId(), - headerAttribsList.toArray(new String[0]), - size, msg.isRedelivered()}; - - CompositeData messageData = new CompositeDataSupport(_messageDataType, - _msgAttributeNames, - itemValues); - _messageList.put(messageData); - } - - return _messageList; - } - - /** - * Creates all the notifications this MBean can send. - * - * @return Notifications broadcasted by this MBean. - */ - @Override - public MBeanNotificationInfo[] getNotificationInfo() - { - String[] notificationTypes = new String[] - {MonitorNotification.THRESHOLD_VALUE_EXCEEDED}; - String name = MonitorNotification.class.getName(); - String description = "An attribute of this MBean has reached threshold value"; - MBeanNotificationInfo info1 = new MBeanNotificationInfo(notificationTypes, - name, - description); - - return new MBeanNotificationInfo[]{info1}; - } - - } // End of AMQMBean class - - public AMQQueue(String name, boolean durable, String owner, - boolean autoDelete, QueueRegistry queueRegistry) - throws AMQException - { - this(name, durable, owner, autoDelete, queueRegistry, - AsyncDeliveryConfig.getAsyncDeliveryExecutor(), new SubscriptionImpl.Factory()); - } - - public AMQQueue(String name, boolean durable, String owner, - boolean autoDelete, QueueRegistry queueRegistry, SubscriptionFactory subscriptionFactory) - throws AMQException - { - this(name, durable, owner, autoDelete, queueRegistry, - AsyncDeliveryConfig.getAsyncDeliveryExecutor(), subscriptionFactory); - } - - public AMQQueue(String name, boolean durable, String owner, - boolean autoDelete, QueueRegistry queueRegistry, Executor asyncDelivery, - SubscriptionFactory subscriptionFactory) - throws AMQException - { - - this(name, durable, owner, autoDelete, queueRegistry, asyncDelivery, new SubscriptionSet(), subscriptionFactory); - } - - public AMQQueue(String name, boolean durable, String owner, - boolean autoDelete, QueueRegistry queueRegistry, Executor asyncDelivery) - throws AMQException - { - - this(name, durable, owner, autoDelete, queueRegistry, asyncDelivery, new SubscriptionSet(), - new SubscriptionImpl.Factory()); - } - - protected AMQQueue(String name, boolean durable, String owner, - boolean autoDelete, QueueRegistry queueRegistry, - SubscriptionSet subscribers, SubscriptionFactory subscriptionFactory) - throws AMQException - { - this(name, durable, owner, autoDelete, queueRegistry, - AsyncDeliveryConfig.getAsyncDeliveryExecutor(), subscribers, subscriptionFactory); - } - - protected AMQQueue(String name, boolean durable, String owner, - boolean autoDelete, QueueRegistry queueRegistry, - SubscriptionSet subscribers) - throws AMQException - { - this(name, durable, owner, autoDelete, queueRegistry, - AsyncDeliveryConfig.getAsyncDeliveryExecutor(), subscribers, new SubscriptionImpl.Factory()); - } - - protected AMQQueue(String name, boolean durable, String owner, - boolean autoDelete, QueueRegistry queueRegistry, - Executor asyncDelivery, SubscriptionSet subscribers, SubscriptionFactory subscriptionFactory) - throws AMQException - { - if (name == null) - { - throw new IllegalArgumentException("Queue name must not be null"); - } - if (queueRegistry == null) - { - throw new IllegalArgumentException("Queue registry must not be null"); - } - _name = name; - _durable = durable; - _owner = owner; - _autoDelete = autoDelete; - _queueRegistry = queueRegistry; - _asyncDelivery = asyncDelivery; - _managedObject = createMBean(); - _managedObject.register(); - _subscribers = subscribers; - _subscriptionFactory = subscriptionFactory; - - //fixme - Pick one. - if (Boolean.getBoolean("concurrentdeliverymanager")) - { - _logger.warn("Using ConcurrentDeliveryManager"); - _deliveryMgr = new ConcurrentDeliveryManager(_subscribers, this); - } - else - { - _logger.warn("Using SynchronizedDeliveryManager"); - _deliveryMgr = new SynchronizedDeliveryManager(_subscribers, this); - } - } - - private AMQQueueMBean createMBean() throws AMQException - { - try - { - return new AMQQueueMBean(); - } - catch (NotCompliantMBeanException ex) - { - throw new AMQException("AMQQueue MBean creation has failed.", ex); - } - } - - public String getName() - { - return _name; - } - - public boolean isShared() - { - return _owner == null; - } - - public boolean isDurable() - { - return _durable; - } - - public String getOwner() - { - return _owner; - } - - public boolean isAutoDelete() - { - return _autoDelete; - } - - public int getMessageCount() - { - return _deliveryMgr.getQueueMessageCount(); - } - - public ManagedObject getManagedObject() - { - return _managedObject; - } - - public void bind(String routingKey, Exchange exchange) - { - _bindings.addBinding(routingKey, exchange); - } - - public void registerProtocolSession(AMQProtocolSession ps, int channel, String consumerTag, boolean acks) - throws AMQException - { - debug("Registering protocol session {0} with channel {1} and consumer tag {2} with {3}", ps, channel, consumerTag, this); - - Subscription subscription = _subscriptionFactory.createSubscription(channel, ps, consumerTag, acks); - _subscribers.addSubscriber(subscription); - } - - public void unregisterProtocolSession(AMQProtocolSession ps, int channel, String consumerTag) throws AMQException - { - debug("Unregistering protocol session {0} with channel {1} and consumer tag {2} from {3}", ps, channel, consumerTag, - this); - - Subscription removedSubscription; - if ((removedSubscription = _subscribers.removeSubscriber(_subscriptionFactory.createSubscription(channel, - ps, - consumerTag))) - == null) - { - throw new AMQException("Protocol session with channel " + channel + " and consumer tag " + consumerTag + - " and protocol session key " + ps.getKey() + " not registered with queue " + this); - } - - // if we are eligible for auto deletion, unregister from the queue registry - if (_autoDelete && _subscribers.isEmpty()) - { - autodelete(); - // we need to manually fire the event to the removed subscription (which was the last one left for this - // queue. This is because the delete method uses the subscription set which has just been cleared - removedSubscription.queueDeleted(this); - } - } - - public int delete(boolean checkUnused, boolean checkEmpty) throws AMQException - { - if (checkUnused && !_subscribers.isEmpty()) - { - _logger.info("Will not delete " + this + " as it is in use."); - return 0; - } - else if (checkEmpty && _deliveryMgr.hasQueuedMessages()) - { - _logger.info("Will not delete " + this + " as it is not empty."); - return 0; - } - else - { - delete(); - return _deliveryMgr.getQueueMessageCount(); - } - } - - public void delete() throws AMQException - { - _subscribers.queueDeleted(this); - _bindings.deregister(); - _queueRegistry.unregisterQueue(_name); - _managedObject.unregister(); - } - - protected void autodelete() throws AMQException - { - debug("autodeleting {0}", this); - delete(); - } - - public void deliver(AMQMessage msg) throws AMQException - { - TxnBuffer buffer = msg.getTxnBuffer(); - if (buffer == null) - { - //non-transactional - record(msg); - process(msg); - } - else - { - buffer.enlist(new Deliver(msg)); - } - } - - private void record(AMQMessage msg) throws AMQException - { - msg.enqueue(this); - msg.incrementReference(); - } - - private void process(AMQMessage msg) throws FailedDequeueException - { - _deliveryMgr.deliver(getName(), msg); - try - { - msg.checkDeliveredToConsumer(); - updateReceivedMessageCount(msg); - } - catch (NoConsumersException e) - { - // as this message will be returned, it should be removed - // from the queue: - dequeue(msg); - } - } - - void dequeue(AMQMessage msg) throws FailedDequeueException - { - try - { - msg.dequeue(this); - msg.decrementReference(); - } - catch (MessageCleanupException e) - { - //Message was dequeued, but could notthen be deleted - //though it is no longer referenced. This should be very - //rare and can be detected and cleaned up on recovery or - //done through some form of manual intervention. - _logger.error(e, e); - } - catch (AMQException e) - { - throw new FailedDequeueException(_name, e); - } - } - - public void deliverAsync() - { - _deliveryMgr.processAsync(_asyncDelivery); - } - - protected SubscriptionManager getSubscribers() - { - return _subscribers; - } - - protected void updateReceivedMessageCount(AMQMessage msg) - { - _totalMessagesReceived++; - _managedObject.checkForNotification(msg); - } - - public boolean equals(Object o) - { - if (this == o) - { - return true; - } - if (o == null || getClass() != o.getClass()) - { - return false; - } - - final AMQQueue amqQueue = (AMQQueue) o; - - return (_name.equals(amqQueue._name)); - } - - public int hashCode() - { - return _name.hashCode(); - } - - public String toString() - { - return "Queue(" + _name + ")@" + System.identityHashCode(this); - } - - private void debug(String msg, Object... args) - { - if (_logger.isDebugEnabled()) - { - _logger.debug(MessageFormat.format(msg, args)); - } - } - - private class Deliver implements TxnOp - { - private final AMQMessage _msg; - - Deliver(AMQMessage msg) - { - _msg = msg; - } - - public void prepare() throws AMQException - { - //do the persistent part of the record() - _msg.enqueue(AMQQueue.this); - } - - public void undoPrepare() - { - } - - public void commit() - { - //do the memeory part of the record() - _msg.incrementReference(); - //then process the message - try - { - process(_msg); - } - catch (FailedDequeueException e) - { - //TODO: is there anything else we can do here? I think not... - _logger.error("Error during commit of a queue delivery: " + e, e); - } - } - - public void rollback() - { - } - } - -} diff --git a/java/broker/src/org/apache/qpid/server/queue/AsyncDeliveryConfig.java b/java/broker/src/org/apache/qpid/server/queue/AsyncDeliveryConfig.java deleted file mode 100644 index ba60c9e003..0000000000 --- a/java/broker/src/org/apache/qpid/server/queue/AsyncDeliveryConfig.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - -import org.apache.qpid.configuration.Configured; -import org.apache.qpid.server.registry.ApplicationRegistry; - -import java.util.concurrent.Executor; -import java.util.concurrent.Executors; - -public class AsyncDeliveryConfig -{ - private Executor _executor; - - @Configured(path = "delivery.poolsize", defaultValue = "0") - public int poolSize; - - public Executor getExecutor() - { - if (_executor == null) - { - if (poolSize > 0) - { - _executor = Executors.newFixedThreadPool(poolSize); - } - else - { - _executor = Executors.newCachedThreadPool(); - } - } - return _executor; - } - - public static Executor getAsyncDeliveryExecutor() - { - return ApplicationRegistry.getInstance().getConfiguredObject(AsyncDeliveryConfig.class).getExecutor(); - } -} diff --git a/java/broker/src/org/apache/qpid/server/queue/ConcurrentDeliveryManager.java b/java/broker/src/org/apache/qpid/server/queue/ConcurrentDeliveryManager.java deleted file mode 100644 index dde76e5ba8..0000000000 --- a/java/broker/src/org/apache/qpid/server/queue/ConcurrentDeliveryManager.java +++ /dev/null @@ -1,348 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; -import org.apache.qpid.util.ConcurrentLinkedQueueAtomicSize; -import org.apache.qpid.configuration.Configured; -import org.apache.qpid.framing.ContentBody; -import org.apache.qpid.server.configuration.Configurator; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.Queue; -import java.util.concurrent.Executor; -import java.util.concurrent.locks.ReentrantLock; -import java.util.concurrent.atomic.AtomicBoolean; - - -/** - * Manages delivery of messages on behalf of a queue - */ -public class ConcurrentDeliveryManager implements DeliveryManager -{ - private static final Logger _log = Logger.getLogger(ConcurrentDeliveryManager.class); - - @Configured(path = "advanced.compressBufferOnQueue", - defaultValue = "false") - public boolean compressBufferOnQueue; - /** - * Holds any queued messages - */ - private final Queue _messages = new ConcurrentLinkedQueueAtomicSize(); - //private int _messageCount; - /** - * Ensures that only one asynchronous task is running for this manager at - * any time. - */ - private final AtomicBoolean _processing = new AtomicBoolean(); - /** - * The subscriptions on the queue to whom messages are delivered - */ - private final SubscriptionManager _subscriptions; - - /** - * A reference to the queue we are delivering messages for. We need this to be able - * to pass the code that handles acknowledgements a handle on the queue. - */ - private final AMQQueue _queue; - - - /** - * Lock used to ensure that an channel that becomes unsuspended during the start of the queueing process is forced - * to wait till the first message is added to the queue. This will ensure that the _queue has messages to be delivered - * via the async thread. - *

      - * Lock is used to control access to hasQueuedMessages() and over the addition of messages to the queue. - */ - private ReentrantLock _lock = new ReentrantLock(); - - - ConcurrentDeliveryManager(SubscriptionManager subscriptions, AMQQueue queue) - { - - //Set values from configuration - Configurator.configure(this); - - if (compressBufferOnQueue) - { - _log.info("Compressing Buffers on queue."); - } - - _subscriptions = subscriptions; - _queue = queue; - } - - /** - * @return boolean if we are queueing - */ - private boolean queueing() - { - return hasQueuedMessages(); - } - - - /** - * @param msg to enqueue - * @return true if we are queue this message - */ - private boolean enqueue(AMQMessage msg) - { - if (msg.isImmediate()) - { - return false; - } - else - { - _lock.lock(); - try - { - if (queueing()) - { - return addMessageToQueue(msg); - } - else - { - return false; - } - } - finally - { - _lock.unlock(); - } - } - } - - private void startQueueing(AMQMessage msg) - { - if (!msg.isImmediate()) - { - addMessageToQueue(msg); - } - } - - private boolean addMessageToQueue(AMQMessage msg) - { - // Shrink the ContentBodies to their actual size to save memory. - if (compressBufferOnQueue) - { - Iterator it = msg.getContentBodies().iterator(); - while (it.hasNext()) - { - ContentBody cb = (ContentBody) it.next(); - cb.reduceBufferToFit(); - } - } - - _messages.offer(msg); - - return true; - } - - - public boolean hasQueuedMessages() - { - - _lock.lock(); - try - { - return !_messages.isEmpty(); - } - finally - { - _lock.unlock(); - } - - - } - - public int getQueueMessageCount() - { - return getMessageCount(); - } - - /** - * This is an EXPENSIVE opperation to perform with a ConcurrentLinkedQueue as it must run the queue to determine size. - * The ConcurrentLinkedQueueAtomicSize uses an AtomicInteger to record the number of elements on the queue. - * - * @return int the number of messages in the delivery queue. - */ - private int getMessageCount() - { - return _messages.size(); - } - - - public synchronized List getMessages() - { - return new ArrayList(_messages); - } - - public synchronized void removeAMessageFromTop() throws AMQException - { - AMQMessage msg = poll(); - if (msg != null) - { - msg.dequeue(_queue); - } - } - - public synchronized void clearAllMessages() throws AMQException - { - AMQMessage msg = poll(); - while (msg != null) - { - msg.dequeue(_queue); - msg = poll(); - } - } - - /** - * Only one thread should ever execute this method concurrently, but - * it can do so while other threads invoke deliver(). - */ - private void processQueue() - { - try - { - boolean hasSubscribers = _subscriptions.hasActiveSubscribers(); - AMQMessage message = peek(); - - //While we have messages to send and subscribers to send them to. - while (message != null && hasSubscribers) - { - // _log.debug("Have messages(" + _messages.size() + ") and subscribers"); - Subscription next = _subscriptions.nextSubscriber(message); - //FIXME Is there still not the chance that this subscribe could be suspended between here and the send? - - //We don't synchronize access to subscribers so need to re-check - if (next != null) - { - next.send(message, _queue); - poll(); - message = peek(); - } - else - { - hasSubscribers = false; - } - } - } - catch (FailedDequeueException e) - { - _log.error("Unable to deliver message as dequeue failed: " + e, e); - } - finally - { - _log.debug("End of processQueue: (" + getQueueMessageCount() + ")" + " subscribers:" + _subscriptions.hasActiveSubscribers()); - } - } - - private AMQMessage peek() - { - return _messages.peek(); - } - - private AMQMessage poll() - { - return _messages.poll(); - } - - Runner asyncDelivery = new Runner(); - - public void processAsync(Executor executor) - { - _log.debug("Processing Async. Queued:" + hasQueuedMessages() + "(" + getQueueMessageCount() + ")" + - " Active:" + _subscriptions.hasActiveSubscribers() + - " Processing:" + _processing.get()); - - if (hasQueuedMessages() && _subscriptions.hasActiveSubscribers()) - { - //are we already running? if so, don't re-run - if (_processing.compareAndSet(false, true)) - { - executor.execute(asyncDelivery); - } - } - } - - public void deliver(String name, AMQMessage msg) throws FailedDequeueException - { - // first check whether we are queueing, and enqueue if we are - if (!enqueue(msg)) - { - // not queueing so deliver message to 'next' subscriber - _lock.lock(); - try - { - Subscription s = _subscriptions.nextSubscriber(msg); - if (s == null) - { - if (!msg.isImmediate()) - { - // no subscribers yet so enter 'queueing' mode and queue this message - startQueueing(msg); - } - } - else - { - s.send(msg, _queue); - msg.setDeliveredToConsumer(); - } - } - finally - { - _lock.unlock(); - } - } - } - - private class Runner implements Runnable - { - public void run() - { - boolean running = true; - while (running) - { - processQueue(); - - //Check that messages have not been added since we did our last peek(); - // Synchronize with the thread that adds to the queue. - // If the queue is still empty then we can exit - _lock.lock(); - try - { - if (!(hasQueuedMessages() && _subscriptions.hasActiveSubscribers())) - { - running = false; - _processing.set(false); - } - } - finally - { - _lock.unlock(); - } - } - } - } -} diff --git a/java/broker/src/org/apache/qpid/server/queue/DefaultQueueRegistry.java b/java/broker/src/org/apache/qpid/server/queue/DefaultQueueRegistry.java deleted file mode 100644 index 3b73072e30..0000000000 --- a/java/broker/src/org/apache/qpid/server/queue/DefaultQueueRegistry.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - -import org.apache.qpid.AMQException; - -import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.ConcurrentHashMap; - -public class DefaultQueueRegistry implements QueueRegistry -{ - private ConcurrentMap _queueMap = new ConcurrentHashMap(); - - public DefaultQueueRegistry() - { - } - - public void registerQueue(AMQQueue queue) throws AMQException - { - _queueMap.put(queue.getName(), queue); - } - - public void unregisterQueue(String name) throws AMQException - { - _queueMap.remove(name); - } - - public AMQQueue getQueue(String name) - { - return _queueMap.get(name); - } -} diff --git a/java/broker/src/org/apache/qpid/server/queue/DeliveryManager.java b/java/broker/src/org/apache/qpid/server/queue/DeliveryManager.java deleted file mode 100644 index dadf86c1d8..0000000000 --- a/java/broker/src/org/apache/qpid/server/queue/DeliveryManager.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - -import org.apache.qpid.AMQException; - -import java.util.concurrent.Executor; -import java.util.List; - -interface DeliveryManager -{ - /** - * Determines whether there are queued messages. Sets _queueing to false if - * there are no queued messages. This needs to be atomic. - * - * @return true if there are queued messages - */ - boolean hasQueuedMessages(); - - /** - * This method should not be used to determin if there are messages in the queue. - * - * @return int The number of messages in the queue - * @use hasQueuedMessages() for all controls relating to having messages on the queue. - */ - int getQueueMessageCount(); - - /** - * Requests that the delivery manager start processing the queue asynchronously - * if there is work that can be done (i.e. there are messages queued up and - * subscribers that can receive them. - *

      - * This should be called when subscribers are added, but only after the consume-ok - * message has been returned as message delivery may start immediately. It should also - * be called after unsuspending a client. - *

      - * - * @param executor the executor on which the delivery should take place - */ - void processAsync(Executor executor); - - /** - * Handles message delivery. The delivery manager is always in one of two modes; - * it is either queueing messages for asynchronous delivery or delivering - * directly. - * - * @param name the name of the entity on whose behalf we are delivering the message - * @param msg the message to deliver - * @throws org.apache.qpid.server.queue.FailedDequeueException if the message could not be dequeued - */ - void deliver(String name, AMQMessage msg) throws FailedDequeueException; - - void removeAMessageFromTop() throws AMQException; - - void clearAllMessages() throws AMQException; - - List getMessages(); -} diff --git a/java/broker/src/org/apache/qpid/server/queue/ExchangeBindings.java b/java/broker/src/org/apache/qpid/server/queue/ExchangeBindings.java deleted file mode 100644 index 684e312fa3..0000000000 --- a/java/broker/src/org/apache/qpid/server/queue/ExchangeBindings.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - -import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.AMQException; - -import java.util.List; -import java.util.HashSet; -import java.util.concurrent.CopyOnWriteArrayList; - -/** - * When a queue is deleted, it should be deregistered from any - * exchange it has been bound to. This class assists in this task, - * by keeping track of all bindings for a given queue. - */ -class ExchangeBindings -{ - static class ExchangeBinding - { - private final Exchange exchange; - private final String routingKey; - - ExchangeBinding(String routingKey, Exchange exchange) - { - this.routingKey = routingKey; - this.exchange = exchange; - } - - void unbind(AMQQueue queue) throws AMQException - { - exchange.deregisterQueue(routingKey, queue); - } - - public Exchange getExchange() - { - return exchange; - } - - public String getRoutingKey() - { - return routingKey; - } - - public int hashCode() - { - return exchange.hashCode() + routingKey.hashCode(); - } - - public boolean equals(Object o) - { - if (!(o instanceof ExchangeBinding)) return false; - ExchangeBinding eb = (ExchangeBinding) o; - return exchange.equals(eb.exchange) && routingKey.equals(eb.routingKey); - } - } - - private final List _bindings = new CopyOnWriteArrayList(); - private final AMQQueue _queue; - - ExchangeBindings(AMQQueue queue) - { - _queue = queue; - } - - /** - * Adds the specified binding to those being tracked. - * @param routingKey the routing key with which the queue whose bindings - * are being tracked by the instance has been bound to the exchange - * @param exchange the exchange bound to - */ - void addBinding(String routingKey, Exchange exchange) - { - _bindings.add(new ExchangeBinding(routingKey, exchange)); - } - - /** - * Deregisters this queue from any exchange it has been bound to - */ - void deregister() throws AMQException - { - //remove duplicates at this point - HashSet copy = new HashSet(_bindings); - for (ExchangeBinding b : copy) - { - b.unbind(_queue); - } - } - - List getExchangeBindings() - { - return _bindings; - } -} diff --git a/java/broker/src/org/apache/qpid/server/queue/FailedDequeueException.java b/java/broker/src/org/apache/qpid/server/queue/FailedDequeueException.java deleted file mode 100644 index b74c49e6e1..0000000000 --- a/java/broker/src/org/apache/qpid/server/queue/FailedDequeueException.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - -import org.apache.qpid.AMQException; - -/** - * Signals that the dequeue of a message from a queue failed - */ -public class FailedDequeueException extends AMQException -{ - public FailedDequeueException(String queue) - { - super("Failed to dequeue message from " + queue); - } - - public FailedDequeueException(String queue, AMQException e) - { - super("Failed to dequeue message from " + queue, e); - } -} diff --git a/java/broker/src/org/apache/qpid/server/queue/ManagedQueue.java b/java/broker/src/org/apache/qpid/server/queue/ManagedQueue.java deleted file mode 100644 index 3a818cf31a..0000000000 --- a/java/broker/src/org/apache/qpid/server/queue/ManagedQueue.java +++ /dev/null @@ -1,220 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - -import org.apache.qpid.server.management.MBeanAttribute; -import org.apache.qpid.server.management.MBeanOperation; -import org.apache.qpid.server.management.MBeanOperationParameter; - -import javax.management.JMException; -import javax.management.MBeanOperationInfo; -import javax.management.openmbean.TabularData; -import javax.management.openmbean.CompositeData; -import java.io.IOException; - -/** - * The management interface exposed to allow management of a queue. - * @author Robert J. Greig - * @author Bhupendra Bhardwaj - * @version 0.1 - */ -public interface ManagedQueue -{ - static final String TYPE = "Queue"; - - /** - * Returns the Name of the ManagedQueue. - * @return the name of the managedQueue. - * @throws IOException - */ - @MBeanAttribute(name="Name", description = "Name of the " + TYPE) - String getName() throws IOException; - - /** - * Tells whether this ManagedQueue is durable or not. - * @return true if this ManagedQueue is a durable queue. - * @throws IOException - */ - @MBeanAttribute(name="Durable", description = "true if the AMQQueue is durable") - boolean isDurable() throws IOException; - - /** - * Tells the Owner of the ManagedQueue. - * @return the owner's name. - * @throws IOException - */ - @MBeanAttribute(name="Owner", description = "Owner") - String getOwner() throws IOException; - - /** - * Tells if the ManagedQueue is set to AutoDelete. - * @return true if the ManagedQueue is set to AutoDelete. - * @throws IOException - */ - @MBeanAttribute(name="AutoDelete", description = "true if the AMQQueue is AutoDelete") - boolean isAutoDelete() throws IOException; - - /** - * Total number of messages on the queue, which are yet to be delivered to the consumer(s). - * @return number of undelivered message in the Queue. - * @throws IOException - */ - @MBeanAttribute(name="MessageCount", - description = "Total number of undelivered messages on the queue") - Integer getMessageCount() throws IOException; - - /** - * Returns the maximum size of a message (in kbytes) allowed to be accepted by the - * ManagedQueue. This is useful in setting notifications or taking - * appropriate action, if the size of the message received is more than - * the allowed size. - * @return the maximum size of a message allowed to be aceepted by the - * ManagedQueue. - * @throws IOException - */ - Long getMaximumMessageSize() throws IOException; - - /** - * Sets the maximum size of the message (in kbytes) that is allowed to be - * accepted by the Queue. - * @param size maximum size of message. - * @throws IOException - */ - @MBeanAttribute(name="MaximumMessageSize", - description="Maximum size(KB) of a message allowed for this Queue") - void setMaximumMessageSize(Long size) throws IOException; - - /** - * Returns the total number of subscribers to the queue. - * @return the number of subscribers. - * @throws IOException - */ - @MBeanAttribute(name="ConsumerCount", description="The total number of subscribers to the queue") - Integer getConsumerCount() throws IOException; - - /** - * Returns the total number of active subscribers to the queue. - * @return the number of active subscribers - * @throws IOException - */ - @MBeanAttribute(name="ActiveConsumerCount", description="The total number of active subscribers to the queue") - Integer getActiveConsumerCount() throws IOException; - - /** - * Tells the total number of messages receieved by the queue since startup. - * @return total number of messages received. - * @throws IOException - */ - @MBeanAttribute(name="ReceivedMessageCount", - description="The total number of messages receieved by the queue since startup") - Long getReceivedMessageCount() throws IOException; - - /** - * Tells the maximum number of messages that can be stored in the queue. - * This is useful in setting the notifications or taking required - * action is the number of message increase this limit. - * @return maximum muber of message allowed to be stored in the queue. - * @throws IOException - */ - Integer getMaximumMessageCount() throws IOException; - - /** - * Sets the maximum number of messages allowed to be stored in the queue. - * @param value the maximum number of messages allowed to be stored in the queue. - * @throws IOException - */ - @MBeanAttribute(name="MaximumMessageCount", - description="The maximum number of messages allowed to be stored in the queue") - void setMaximumMessageCount(Integer value) throws IOException; - - /** - * Size of messages in the queue - * @return - * @throws IOException - */ - @MBeanAttribute(name="QueueSize", description="Size of messages(KB) in the queue") - Long getQueueSize() throws IOException; - - /** - * Tells the maximum size of all the messages combined together, - * that can be stored in the queue. This is useful for setting notifications - * or taking required action if the size of messages stored in the queue - * increases over this limit. - * @return maximum size of the all the messages allowed for the queue. - * @throws IOException - */ - Long getQueueDepth() throws IOException; - - /** - * Sets the maximum size of all the messages together, that can be stored - * in the queue. - * @param value - * @throws IOException - */ - @MBeanAttribute(name="QueueDepth", - description="The size(KB) of all the messages together, that can be stored in the queue") - void setQueueDepth(Long value) throws IOException; - - - - //********** Operations *****************// - - - /** - * Returns a subset of all the messages stored in the queue. The messages - * are returned based on the given index numbers. - * @param fromIndex - * @param toIndex - * @return - * @throws IOException - * @throws JMException - */ - @MBeanOperation(name="viewMessages", - description="shows messages in this queue with given indexes. eg. from index 1 - 100") - TabularData viewMessages(@MBeanOperationParameter(name="from index", description="from index")int fromIndex, - @MBeanOperationParameter(name="to index", description="to index")int toIndex) - throws IOException, JMException; - - /** - * Deletes the first message from top. - * @throws IOException - * @throws JMException - */ - @MBeanOperation(name="deleteMessageFromTop", - description="Deletes the first message from top", - impact= MBeanOperationInfo.ACTION) - void deleteMessageFromTop() throws IOException, JMException; - - /** - * Clears the queue by deleting all the undelivered messages from the queue. - * @throws IOException - * @throws JMException - */ - @MBeanOperation(name="clearQueue", - description="Clears the queue by deleting all the undelivered messages from the queue", - impact= MBeanOperationInfo.ACTION) - void clearQueue() throws IOException, JMException; - - @MBeanOperation(name="viewMessageContent", - description="Returns the message content along with MimeType and Encoding") - CompositeData viewMessageContent(@MBeanOperationParameter(name="Message Id", description="Message Id")long messageId) - throws IOException, JMException; -} diff --git a/java/broker/src/org/apache/qpid/server/queue/MessageCleanupException.java b/java/broker/src/org/apache/qpid/server/queue/MessageCleanupException.java deleted file mode 100644 index bfe0a0ecf1..0000000000 --- a/java/broker/src/org/apache/qpid/server/queue/MessageCleanupException.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - -import org.apache.qpid.AMQException; - -/** - * Signals that the removal of a message once its refcount reached - * zero failed. - */ -public class MessageCleanupException extends AMQException -{ - public MessageCleanupException(long messageId, AMQException e) - { - super("Failed to cleanup message with id " + messageId, e); - } -} diff --git a/java/broker/src/org/apache/qpid/server/queue/NoConsumersException.java b/java/broker/src/org/apache/qpid/server/queue/NoConsumersException.java deleted file mode 100644 index 2d37b806f6..0000000000 --- a/java/broker/src/org/apache/qpid/server/queue/NoConsumersException.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - -import org.apache.qpid.server.RequiredDeliveryException; -import org.apache.qpid.framing.ContentHeaderBody; -import org.apache.qpid.framing.ContentBody; -import org.apache.qpid.framing.BasicPublishBody; -import org.apache.qpid.protocol.AMQConstant; - -import java.util.List; - -/** - * Signals that no consumers exist for a message at a given point in time. - * Used if a message has immediate=true and there are no consumers registered - * with the queue. - */ -public class NoConsumersException extends RequiredDeliveryException -{ - public NoConsumersException(String queue, - BasicPublishBody publishBody, - ContentHeaderBody contentHeaderBody, - List contentBodies) - { - super("Immediate delivery to " + queue + " is not possible.", publishBody, contentHeaderBody, contentBodies); - } - - public NoConsumersException(BasicPublishBody publishBody, - ContentHeaderBody contentHeaderBody, - List contentBodies) - { - super("Immediate delivery is not possible.", publishBody, contentHeaderBody, contentBodies); - } - - public int getReplyCode() - { - return AMQConstant.NO_CONSUMERS.getCode(); - } -} diff --git a/java/broker/src/org/apache/qpid/server/queue/QueueRegistry.java b/java/broker/src/org/apache/qpid/server/queue/QueueRegistry.java deleted file mode 100644 index c83f17b98c..0000000000 --- a/java/broker/src/org/apache/qpid/server/queue/QueueRegistry.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - -import org.apache.qpid.AMQException; - - -public interface QueueRegistry -{ - void registerQueue(AMQQueue queue) throws AMQException; - - void unregisterQueue(String name) throws AMQException; - - AMQQueue getQueue(String name); -} diff --git a/java/broker/src/org/apache/qpid/server/queue/Subscription.java b/java/broker/src/org/apache/qpid/server/queue/Subscription.java deleted file mode 100644 index dfc16a7c71..0000000000 --- a/java/broker/src/org/apache/qpid/server/queue/Subscription.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - -import org.apache.qpid.AMQException; - -public interface Subscription -{ - void send(AMQMessage msg, AMQQueue queue) throws FailedDequeueException; - - boolean isSuspended(); - - void queueDeleted(AMQQueue queue); -} diff --git a/java/broker/src/org/apache/qpid/server/queue/SubscriptionFactory.java b/java/broker/src/org/apache/qpid/server/queue/SubscriptionFactory.java deleted file mode 100644 index 0fd44e4fbc..0000000000 --- a/java/broker/src/org/apache/qpid/server/queue/SubscriptionFactory.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.AMQException; - -/** - * Allows the customisation of the creation of a subscription. This is typically done within an AMQQueue. This - * factory primarily assists testing although in future more sophisticated subscribers may need a different - * subscription implementation. - * - * @see org.apache.qpid.server.queue.AMQQueue - */ -public interface SubscriptionFactory -{ - Subscription createSubscription(int channel, AMQProtocolSession protocolSession, String consumerTag, boolean acks) - throws AMQException; - - Subscription createSubscription(int channel, AMQProtocolSession protocolSession,String consumerTag) - throws AMQException; -} diff --git a/java/broker/src/org/apache/qpid/server/queue/SubscriptionImpl.java b/java/broker/src/org/apache/qpid/server/queue/SubscriptionImpl.java deleted file mode 100644 index 5cad28b80d..0000000000 --- a/java/broker/src/org/apache/qpid/server/queue/SubscriptionImpl.java +++ /dev/null @@ -1,191 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - -import org.apache.log4j.Logger; -import org.apache.mina.common.ByteBuffer; -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQDataBlock; -import org.apache.qpid.framing.AMQFrame; -import org.apache.qpid.framing.BasicDeliverBody; -import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.server.protocol.AMQProtocolSession; - -/** - * Encapsulation of a supscription to a queue. - *

      - * Ties together the protocol session of a subscriber, the consumer tag that - * was given out by the broker and the channel id. - *

      - */ -public class SubscriptionImpl implements Subscription -{ - private static final Logger _logger = Logger.getLogger(SubscriptionImpl.class); - - public final AMQChannel channel; - - public final AMQProtocolSession protocolSession; - - public final String consumerTag; - - private final Object sessionKey; - - /** - * True if messages need to be acknowledged - */ - private final boolean _acks; - - public static class Factory implements SubscriptionFactory - { - public SubscriptionImpl createSubscription(int channel, AMQProtocolSession protocolSession, String consumerTag, boolean acks) - throws AMQException - { - return new SubscriptionImpl(channel, protocolSession, consumerTag, acks); - } - - public SubscriptionImpl createSubscription(int channel, AMQProtocolSession protocolSession, String consumerTag) - throws AMQException - { - return new SubscriptionImpl(channel, protocolSession, consumerTag); - } - } - - public SubscriptionImpl(int channelId, AMQProtocolSession protocolSession, - String consumerTag, boolean acks) - throws AMQException - { - AMQChannel channel = protocolSession.getChannel(channelId); - if (channel == null) - { - throw new NullPointerException("channel not found in protocol session"); - } - - this.channel = channel; - this.protocolSession = protocolSession; - this.consumerTag = consumerTag; - sessionKey = protocolSession.getKey(); - _acks = acks; - } - - public SubscriptionImpl(int channel, AMQProtocolSession protocolSession, - String consumerTag) - throws AMQException - { - this(channel, protocolSession, consumerTag, false); - } - - public boolean equals(Object o) - { - return (o instanceof SubscriptionImpl) && equals((SubscriptionImpl) o); - } - - /** - * Equality holds if the session matches and the channel and consumer tag are the same. - */ - private boolean equals(SubscriptionImpl psc) - { - return sessionKey.equals(psc.sessionKey) - && psc.channel == channel - && psc.consumerTag.equals(consumerTag); - } - - public int hashCode() - { - return sessionKey.hashCode(); - } - - public String toString() - { - return "[channel=" + channel + ", consumerTag=" + consumerTag + ", session=" + protocolSession.getKey() + "]"; - } - - /** - * This method can be called by each of the publisher threads. - * As a result all changes to the channel object must be thread safe. - * - * @param msg - * @param queue - * @throws AMQException - */ - public void send(AMQMessage msg, AMQQueue queue) throws FailedDequeueException - { - if (msg != null) - { - // if we do not need to wait for client acknowledgements - // we can decrement the reference count immediately. - - // By doing this _before_ the send we ensure that it - // doesn't get sent if it can't be dequeued, preventing - // duplicate delivery on recovery. - - // The send may of course still fail, in which case, as - // the message is unacked, it will be lost. - if (!_acks) - { - queue.dequeue(msg); - } - synchronized(channel) - { - long deliveryTag = channel.getNextDeliveryTag(); - - if (_acks) - { - channel.addUnacknowledgedMessage(msg, deliveryTag, consumerTag, queue); - } - - ByteBuffer deliver = createEncodedDeliverFrame(deliveryTag, msg.getRoutingKey(), msg.getExchangeName()); - AMQDataBlock frame = msg.getDataBlock(deliver, channel.getChannelId()); - - protocolSession.writeFrame(frame); - } - } - else - { - _logger.error("Attempt to send Null message", new NullPointerException()); - } - } - - public boolean isSuspended() - { - return channel.isSuspended(); - } - - /** - * Callback indicating that a queue has been deleted. - * - * @param queue - */ - public void queueDeleted(AMQQueue queue) - { - channel.queueDeleted(queue); - } - - private ByteBuffer createEncodedDeliverFrame(long deliveryTag, String routingKey, String exchange) - { - AMQFrame deliverFrame = BasicDeliverBody.createAMQFrame(channel.getChannelId(), consumerTag, - deliveryTag, false, exchange, - routingKey); - ByteBuffer buf = ByteBuffer.allocate((int) deliverFrame.getSize()); // XXX: Could cast be a problem? - deliverFrame.writePayload(buf); - buf.flip(); - return buf; - } -} diff --git a/java/broker/src/org/apache/qpid/server/queue/SubscriptionManager.java b/java/broker/src/org/apache/qpid/server/queue/SubscriptionManager.java deleted file mode 100644 index 353b461c8d..0000000000 --- a/java/broker/src/org/apache/qpid/server/queue/SubscriptionManager.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - -/** - * Abstraction of actor that will determine the subscriber to whom - * a message will be sent. - */ -public interface SubscriptionManager -{ - public boolean hasActiveSubscribers(); - public Subscription nextSubscriber(AMQMessage msg); -} diff --git a/java/broker/src/org/apache/qpid/server/queue/SubscriptionSet.java b/java/broker/src/org/apache/qpid/server/queue/SubscriptionSet.java deleted file mode 100644 index 7cc3f5f719..0000000000 --- a/java/broker/src/org/apache/qpid/server/queue/SubscriptionSet.java +++ /dev/null @@ -1,183 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - -import org.apache.log4j.Logger; -import java.util.List; -import java.util.ListIterator; -import java.util.concurrent.CopyOnWriteArrayList; - -/** - * Holds a set of subscriptions for a queue and manages the round - * robin-ing of deliver etc. - */ -class SubscriptionSet implements WeightedSubscriptionManager -{ - private static final Logger _log = Logger.getLogger(SubscriptionSet.class); - - /** - * List of registered subscribers - */ - private List _subscriptions = new CopyOnWriteArrayList(); - - /** - * Used to control the round robin delivery of content - */ - private int _currentSubscriber; - - /** - * Accessor for unit tests. - */ - int getCurrentSubscriber() - { - return _currentSubscriber; - } - - public void addSubscriber(Subscription subscription) - { - _subscriptions.add(subscription); - } - - /** - * Remove the subscription, returning it if it was found - * @param subscription - * @return null if no match was found - */ - public Subscription removeSubscriber(Subscription subscription) - { - boolean isRemoved = _subscriptions.remove(subscription); // TODO: possibly need O(1) operation here. - if (isRemoved) - { - return subscription; - } - else - { - debugDumpSubscription(subscription); - return null; - } - } - - private void debugDumpSubscription(Subscription subscription) - { - if (_log.isDebugEnabled()) - { - _log.debug("Subscription " + subscription + " not found. Dumping subscriptions:"); - for (Subscription s : _subscriptions) - { - _log.debug("Subscription: " + s); - } - _log.debug("Subscription dump complete"); - } - } - - /** - * Return the next unsuspended subscription or null if not found. - * - * Performance note: - * This method can scan all items twice when looking for a subscription that is not - * suspended. The worst case occcurs when all subscriptions are suspended. However, it is does this - * without synchronisation and subscriptions may be added and removed concurrently. Also note that because of - * race conditions and when subscriptions are removed between calls to nextSubscriber, the - * IndexOutOfBoundsException also causes the scan to start at the beginning. - */ - public Subscription nextSubscriber(AMQMessage msg) - { - if (_subscriptions.isEmpty()) - { - return null; - } - - try { - final Subscription result = nextSubscriber(); - if (result == null) { - _currentSubscriber = 0; - return nextSubscriber(); - } else { - return result; - } - } catch (IndexOutOfBoundsException e) { - _currentSubscriber = 0; - return nextSubscriber(); - } - } - - private Subscription nextSubscriber() - { - final ListIterator iterator = _subscriptions.listIterator(_currentSubscriber); - while (iterator.hasNext()) { - Subscription subscription = iterator.next(); - ++_currentSubscriber; - subscriberScanned(); - if (!subscription.isSuspended()) { - return subscription; - } - } - return null; - } - - /** - * Overridden in test classes. - */ - protected void subscriberScanned() - { - } - - public boolean isEmpty() - { - return _subscriptions.isEmpty(); - } - - public boolean hasActiveSubscribers() - { - for (Subscription s : _subscriptions) - { - if (!s.isSuspended()) return true; - } - return false; - } - - public int getWeight() - { - int count = 0; - for (Subscription s : _subscriptions) - { - if (!s.isSuspended()) count++; - } - return count; - } - - /** - * Notification that a queue has been deleted. This is called so that the subscription can inform the - * channel, which in turn can update its list of unacknowledged messages. - * @param queue - */ - public void queueDeleted(AMQQueue queue) - { - for (Subscription s : _subscriptions) - { - s.queueDeleted(queue); - } - } - - int size() { - return _subscriptions.size(); - } -} diff --git a/java/broker/src/org/apache/qpid/server/queue/SynchronizedDeliveryManager.java b/java/broker/src/org/apache/qpid/server/queue/SynchronizedDeliveryManager.java deleted file mode 100644 index d2e53717af..0000000000 --- a/java/broker/src/org/apache/qpid/server/queue/SynchronizedDeliveryManager.java +++ /dev/null @@ -1,255 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - -import org.apache.qpid.AMQException; -import org.apache.log4j.Logger; - -import java.util.LinkedList; -import java.util.Queue; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.Executor; -import java.util.concurrent.atomic.AtomicBoolean; - -/** - * Manages delivery of messages on behalf of a queue - */ -class SynchronizedDeliveryManager implements DeliveryManager -{ - private static final Logger _log = Logger.getLogger(ConcurrentDeliveryManager.class); - - /** - * Holds any queued messages - */ - private final Queue _messages = new LinkedList(); - /** - * Ensures that only one asynchronous task is running for this manager at - * any time. - */ - private final AtomicBoolean _processing = new AtomicBoolean(); - /** - * The subscriptions on the queue to whom messages are delivered - */ - private final SubscriptionManager _subscriptions; - - /** - * An indication of the mode we are in. If this is true then messages are - * being queued up in _messages for asynchronous delivery. If it is false - * then messages can be delivered directly as they come in. - */ - private volatile boolean _queueing; - - /** - * A reference to the queue we are delivering messages for. We need this to be able - * to pass the code that handles acknowledgements a handle on the queue. - */ - private final AMQQueue _queue; - - SynchronizedDeliveryManager(SubscriptionManager subscriptions, AMQQueue queue) - { - _subscriptions = subscriptions; - _queue = queue; - } - - private synchronized boolean enqueue(AMQMessage msg) - { - if (msg.isImmediate()) - { - return false; - } - else - { - if (_queueing) - { - _messages.offer(msg); - return true; - } - else - { - return false; - } - } - } - - private synchronized void startQueueing(AMQMessage msg) - { - _queueing = true; - enqueue(msg); - } - - /** - * Determines whether there are queued messages. Sets _queueing to false if - * there are no queued messages. This needs to be atomic. - * - * @return true if there are queued messages - */ - public synchronized boolean hasQueuedMessages() - { - boolean empty = _messages.isEmpty(); - if (empty) - { - _queueing = false; - } - return !empty; - } - - public synchronized int getQueueMessageCount() - { - return _messages.size(); - } - - public synchronized List getMessages() - { - return new ArrayList(_messages); - } - - public synchronized void removeAMessageFromTop() throws AMQException - { - AMQMessage msg = poll(); - if (msg != null) - { - msg.dequeue(_queue); - } - } - - public synchronized void clearAllMessages() throws AMQException - { - AMQMessage msg = poll(); - while (msg != null) - { - msg.dequeue(_queue); - msg = poll(); - } - } - - /** - * Only one thread should ever execute this method concurrently, but - * it can do so while other threads invoke deliver(). - */ - private void processQueue() - { - try - { - boolean hasSubscribers = _subscriptions.hasActiveSubscribers(); - while (hasQueuedMessages() && hasSubscribers) - { - Subscription next = _subscriptions.nextSubscriber(peek()); - //We don't synchronize access to subscribers so need to re-check - if (next != null) - { - try - { - next.send(poll(), _queue); - } - catch (AMQException e) - { - _log.error("Unable to deliver message: " + e, e); - } - } - else - { - hasSubscribers = false; - } - } - } - finally - { - _processing.set(false); - } - } - - private synchronized AMQMessage peek() - { - return _messages.peek(); - } - - private synchronized AMQMessage poll() - { - return _messages.poll(); - } - - /** - * Requests that the delivery manager start processing the queue asynchronously - * if there is work that can be done (i.e. there are messages queued up and - * subscribers that can receive them. - *

      - * This should be called when subscribers are added, but only after the consume-ok - * message has been returned as message delivery may start immediately. It should also - * be called after unsuspending a client. - *

      - * - * @param executor the executor on which the delivery should take place - */ - public void processAsync(Executor executor) - { - if (hasQueuedMessages() && _subscriptions.hasActiveSubscribers()) - { - //are we already running? if so, don't re-run - if (_processing.compareAndSet(false, true)) - { - executor.execute(new Runner()); - } - } - } - - /** - * Handles message delivery. The delivery manager is always in one of two modes; - * it is either queueing messages for asynchronous delivery or delivering - * directly. - * - * @param name the name of the entity on whose behalf we are delivering the message - * @param msg the message to deliver - * @throws NoConsumersException if there are no active subscribers to deliver - * the message to - */ - public void deliver(String name, AMQMessage msg) throws FailedDequeueException - { - // first check whether we are queueing, and enqueue if we are - if (!enqueue(msg)) - { - synchronized(this) - { - // not queueing so deliver message to 'next' subscriber - Subscription s = _subscriptions.nextSubscriber(msg); - if (s == null) - { - // no subscribers yet so enter 'queueing' mode and queue this message - startQueueing(msg); - } - else - { - s.send(msg, _queue); - msg.setDeliveredToConsumer(); - } - } - } - - } - - private class Runner implements Runnable - { - public void run() - { - processQueue(); - } - } -} diff --git a/java/broker/src/org/apache/qpid/server/queue/WeightedSubscriptionManager.java b/java/broker/src/org/apache/qpid/server/queue/WeightedSubscriptionManager.java deleted file mode 100644 index 6c71571807..0000000000 --- a/java/broker/src/org/apache/qpid/server/queue/WeightedSubscriptionManager.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - -public interface WeightedSubscriptionManager extends SubscriptionManager -{ - public int getWeight(); -} diff --git a/java/broker/src/org/apache/qpid/server/registry/ApplicationRegistry.java b/java/broker/src/org/apache/qpid/server/registry/ApplicationRegistry.java deleted file mode 100644 index 48331843e5..0000000000 --- a/java/broker/src/org/apache/qpid/server/registry/ApplicationRegistry.java +++ /dev/null @@ -1,200 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.registry; - -import org.apache.commons.configuration.Configuration; -import org.apache.log4j.Logger; -import org.apache.qpid.server.configuration.Configurator; - -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; - -/** - * An abstract application registry that provides access to configuration information and handles the - * construction and caching of configurable objects. - *

      - * Subclasses should handle the construction of the "registered objects" such as the exchange registry. - */ -public abstract class ApplicationRegistry implements IApplicationRegistry -{ - private static final Logger _logger = Logger.getLogger(ApplicationRegistry.class); - - private static Map _instanceMap = new HashMap(); - - private final Map, Object> _configuredObjects = new HashMap, Object>(); - - protected final Configuration _configuration; - - public static final int DEFAULT_INSTANCE = 1; - public static final String DEFAULT_APPLICATION_REGISTRY = "org.apache.qpid.server.util.NullApplicationRegistry"; - public static String _APPLICATION_REGISTRY = DEFAULT_APPLICATION_REGISTRY; - - static - { - Runtime.getRuntime().addShutdownHook(new Thread(new ShutdownService())); - } - - private static class ShutdownService implements Runnable - { - public void run() - { - _logger.info("Shutting down application registries..."); - try - { - synchronized (ApplicationRegistry.class) - { - Iterator keyIterator = _instanceMap.keySet().iterator(); - - while (keyIterator.hasNext()) - { - int key = (Integer) keyIterator.next(); - IApplicationRegistry instance = (IApplicationRegistry) _instanceMap.get(key); - - if ((instance != null)) - { - if (instance.getMessageStore() != null) - { - instance.getMessageStore().close(); - } - } - } - } - } - catch (Exception e) - { - _logger.error("Error shutting down message store: " + e, e); - } - } - } - - public static void initialise(IApplicationRegistry instance) throws Exception - { - initialise(instance, DEFAULT_INSTANCE); - } - - public static void initialise(IApplicationRegistry instance, int instanceID) throws Exception - { - if (instance != null) - { - _logger.info("Initialising Application Registry:" + instanceID); - _instanceMap.put(instanceID, instance); - - try - { - instance.initialise(); - } - catch (Exception e) - { - _instanceMap.remove(instanceID); - throw e; - } - } - else - { - remove(instanceID); - } - } - - public static void remove(int instanceID) - { - try - { - ((IApplicationRegistry) _instanceMap.get(instanceID)).getMessageStore().close(); - } - catch (Exception e) - { - - } - finally - { - _instanceMap.remove(instanceID); - } - } - - - protected ApplicationRegistry(Configuration configuration) - { - _configuration = configuration; - } - - public static IApplicationRegistry getInstance() - { - return getInstance(DEFAULT_INSTANCE); - } - - public static IApplicationRegistry getInstance(int instanceID) - { - IApplicationRegistry instance = (IApplicationRegistry) _instanceMap.get(instanceID); - - if (instance == null) - { - try - { - _logger.info("Creating DEFAULT_APPLICATION_REGISTRY: " + _APPLICATION_REGISTRY + " : Instance:" + instanceID); - IApplicationRegistry registry = (IApplicationRegistry) Class.forName(_APPLICATION_REGISTRY).getConstructor((Class[]) null).newInstance((Object[]) null); - ApplicationRegistry.initialise(registry, instanceID); - _logger.info("Initialised Application Registry:" + instanceID); - return registry; - } - catch (Exception e) - { - _logger.error("Error configuring application: " + e, e); - //throw new AMQBrokerCreationException(instanceID, "Unable to create Application Registry instance " + instanceID); - throw new RuntimeException("Unable to create Application Registry"); - } - } - else - { - return instance; - } - } - - public Configuration getConfiguration() - { - return _configuration; - } - - public T getConfiguredObject(Class instanceType) - { - T instance = (T) _configuredObjects.get(instanceType); - if (instance == null) - { - try - { - instance = instanceType.newInstance(); - } - catch (Exception e) - { - _logger.error("Unable to instantiate configuration class " + instanceType + " - ensure it has a public default constructor"); - throw new IllegalArgumentException("Unable to instantiate configuration class " + instanceType + " - ensure it has a public default constructor"); - } - Configurator.configure(instance); - _configuredObjects.put(instanceType, instance); - } - return instance; - } - - public static void setDefaultApplicationRegistry(String clazz) - { - _APPLICATION_REGISTRY = clazz; - } -} diff --git a/java/broker/src/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java b/java/broker/src/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java deleted file mode 100644 index 1eb490d6fb..0000000000 --- a/java/broker/src/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java +++ /dev/null @@ -1,158 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.registry; - -import org.apache.commons.configuration.CompositeConfiguration; -import org.apache.commons.configuration.Configuration; -import org.apache.commons.configuration.ConfigurationException; -import org.apache.commons.configuration.SystemConfiguration; -import org.apache.commons.configuration.XMLConfiguration; -import org.apache.qpid.server.exchange.DefaultExchangeFactory; -import org.apache.qpid.server.exchange.DefaultExchangeRegistry; -import org.apache.qpid.server.exchange.ExchangeFactory; -import org.apache.qpid.server.exchange.ExchangeRegistry; -import org.apache.qpid.server.management.JMXManagedObjectRegistry; -import org.apache.qpid.server.management.ManagedObjectRegistry; -import org.apache.qpid.server.management.ManagementConfiguration; -import org.apache.qpid.server.management.NoopManagedObjectRegistry; -import org.apache.qpid.server.queue.DefaultQueueRegistry; -import org.apache.qpid.server.queue.QueueRegistry; -import org.apache.qpid.server.security.auth.AuthenticationManager; -import org.apache.qpid.server.security.auth.SASLAuthenticationManager; -import org.apache.qpid.server.store.MessageStore; - -import java.io.File; - -public class ConfigurationFileApplicationRegistry extends ApplicationRegistry -{ - private QueueRegistry _queueRegistry; - - private ExchangeRegistry _exchangeRegistry; - - private ExchangeFactory _exchangeFactory; - - private ManagedObjectRegistry _managedObjectRegistry; - - private AuthenticationManager _authenticationManager; - - private MessageStore _messageStore; - - public ConfigurationFileApplicationRegistry(File configurationURL) throws ConfigurationException - { - super(config(configurationURL)); - } - - // Our configuration class needs to make the interpolate method - // public so it can be called below from the config method. - private static class MyConfiguration extends CompositeConfiguration { - public String interpolate(String obj) { - return super.interpolate(obj); - } - } - - private static final Configuration config(File url) throws ConfigurationException { - // We have to override the interpolate methods so that - // interpolation takes place accross the entirety of the - // composite configuration. Without doing this each - // configuration object only interpolates variables defined - // inside itself. - final MyConfiguration conf = new MyConfiguration(); - conf.addConfiguration(new SystemConfiguration() { - protected String interpolate(String o) { - return conf.interpolate(o); - } - }); - conf.addConfiguration(new XMLConfiguration(url) { - protected String interpolate(String o) { - return conf.interpolate(o); - } - }); - return conf; - } - - public void initialise() throws Exception - { - initialiseManagedObjectRegistry(); - _queueRegistry = new DefaultQueueRegistry(); - _exchangeFactory = new DefaultExchangeFactory(); - _exchangeRegistry = new DefaultExchangeRegistry(_exchangeFactory); - _authenticationManager = new SASLAuthenticationManager(); - initialiseMessageStore(); - } - - private void initialiseManagedObjectRegistry() - { - ManagementConfiguration config = getConfiguredObject(ManagementConfiguration.class); - if (config.enabled) - { - _managedObjectRegistry = new JMXManagedObjectRegistry(); - } - else - { - _managedObjectRegistry = new NoopManagedObjectRegistry(); - } - } - - private void initialiseMessageStore() throws Exception - { - String messageStoreClass = _configuration.getString("store.class"); - Class clazz = Class.forName(messageStoreClass); - Object o = clazz.newInstance(); - - if (!(o instanceof MessageStore)) - { - throw new Exception("Message store class must implement " + MessageStore.class + ". Class " + clazz + - " does not."); - } - _messageStore = (MessageStore) o; - _messageStore.configure(getQueueRegistry(), "store", _configuration); - } - - public QueueRegistry getQueueRegistry() - { - return _queueRegistry; - } - - public ExchangeRegistry getExchangeRegistry() - { - return _exchangeRegistry; - } - - public ExchangeFactory getExchangeFactory() - { - return _exchangeFactory; - } - - public ManagedObjectRegistry getManagedObjectRegistry() - { - return _managedObjectRegistry; - } - - public AuthenticationManager getAuthenticationManager() - { - return _authenticationManager; - } - - public MessageStore getMessageStore() - { - return _messageStore; - } -} diff --git a/java/broker/src/org/apache/qpid/server/registry/IApplicationRegistry.java b/java/broker/src/org/apache/qpid/server/registry/IApplicationRegistry.java deleted file mode 100644 index cd664f9a4b..0000000000 --- a/java/broker/src/org/apache/qpid/server/registry/IApplicationRegistry.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.registry; - -import org.apache.qpid.server.exchange.ExchangeFactory; -import org.apache.qpid.server.exchange.ExchangeRegistry; -import org.apache.qpid.server.queue.QueueRegistry; -import org.apache.qpid.server.management.ManagedObjectRegistry; -import org.apache.qpid.server.security.auth.AuthenticationManager; -import org.apache.qpid.server.store.MessageStore; -import org.apache.commons.configuration.Configuration; - -public interface IApplicationRegistry -{ - /** - * Initialise the application registry. All initialisation must be done in this method so that any components - * that need access to the application registry itself for initialisation are able to use it. Attempting to - * initialise in the constructor will lead to failures since the registry reference will not have been set. - */ - void initialise() throws Exception; - - /** - * This gets access to a "configured object". A configured object has fields populated from a the configuration - * object (Commons Configuration) automatically, where it has the appropriate attributes defined on fields. - * Application registry implementations can choose the refresh strategy or caching approach. - * @param instanceType the type of object you want initialised. This must be unique - i.e. you can only - * have a single object of this type in the system. - * @return the configured object - */ - T getConfiguredObject(Class instanceType); - - /** - * Get the low level configuration. For use cases where the configured object approach is not required - * you can get the complete configuration information. - * @return a Commons Configuration instance - */ - Configuration getConfiguration(); - - QueueRegistry getQueueRegistry(); - - ExchangeRegistry getExchangeRegistry(); - - ExchangeFactory getExchangeFactory(); - - ManagedObjectRegistry getManagedObjectRegistry(); - - AuthenticationManager getAuthenticationManager(); - - MessageStore getMessageStore(); -} diff --git a/java/broker/src/org/apache/qpid/server/security/auth/AuthenticationManager.java b/java/broker/src/org/apache/qpid/server/security/auth/AuthenticationManager.java deleted file mode 100644 index 9f4addd7ee..0000000000 --- a/java/broker/src/org/apache/qpid/server/security/auth/AuthenticationManager.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.security.auth; - -import javax.security.sasl.SaslException; -import javax.security.sasl.SaslServer; - -public interface AuthenticationManager -{ - String getMechanisms(); - - SaslServer createSaslServer(String mechanism, String localFQDN) throws SaslException; - - AuthenticationResult authenticate(SaslServer server, byte[] response); -} diff --git a/java/broker/src/org/apache/qpid/server/security/auth/AuthenticationProviderInitialiser.java b/java/broker/src/org/apache/qpid/server/security/auth/AuthenticationProviderInitialiser.java deleted file mode 100644 index b26ba9b3dd..0000000000 --- a/java/broker/src/org/apache/qpid/server/security/auth/AuthenticationProviderInitialiser.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.security.auth; - -import org.apache.commons.configuration.Configuration; - -import javax.security.auth.callback.CallbackHandler; -import javax.security.sasl.SaslServerFactory; -import java.util.Map; - -public interface AuthenticationProviderInitialiser -{ - /** - * @return the mechanism's name. This will be used in the list of mechanism's advertised to the - * client. - */ - String getMechanismName(); - - /** - * Initialise the authentication provider. - * @param baseConfigPath the path in the config file that points to any config options for this provider. Each - * provider can have its own set of configuration options - * @param configuration the Apache Commons Configuration instance used to configure this provider - * @param principalDatabases the set of principal databases that are available - */ - void initialise(String baseConfigPath, Configuration configuration, - Map principalDatabases) throws Exception; - - /** - * @return the callback handler that should be used to process authentication requests for this mechanism. This will - * be called after initialise and will be stored by the authentication manager. The callback handler must be - * fully threadsafe. - */ - CallbackHandler getCallbackHandler(); - - /** - * Get the properties that must be passed in to the Sasl.createSaslServer method. - * @return the properties, which may be null - */ - Map getProperties(); - - /** - * Get the class that is the server factory. This is used for the JCA registration. - * @return null if no JCA registration is required, otherwise return the class - * that will be used in JCA registration - */ - Class getServerFactoryClassForJCARegistration(); -} diff --git a/java/broker/src/org/apache/qpid/server/security/auth/AuthenticationResult.java b/java/broker/src/org/apache/qpid/server/security/auth/AuthenticationResult.java deleted file mode 100644 index 0e3aea4de0..0000000000 --- a/java/broker/src/org/apache/qpid/server/security/auth/AuthenticationResult.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.security.auth; - -public class AuthenticationResult -{ - public enum AuthenticationStatus - { - SUCCESS, CONTINUE, ERROR - } - - public AuthenticationStatus status; - public byte[] challenge; - - public AuthenticationResult(byte[] challenge, AuthenticationStatus status) - { - this.status = status; - this.challenge = challenge; - } - - public AuthenticationResult(AuthenticationStatus status) - { - this.status = status; - } -} diff --git a/java/broker/src/org/apache/qpid/server/security/auth/CRAMMD5Initialiser.java b/java/broker/src/org/apache/qpid/server/security/auth/CRAMMD5Initialiser.java deleted file mode 100644 index 4e428bbf23..0000000000 --- a/java/broker/src/org/apache/qpid/server/security/auth/CRAMMD5Initialiser.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.security.auth; - -import javax.security.sasl.SaslServerFactory; - -public class CRAMMD5Initialiser extends UsernamePasswordInitialiser -{ - public String getMechanismName() - { - return "CRAM-MD5"; - } - - public Class getServerFactoryClassForJCARegistration() - { - // since the CRAM-MD5 provider is registered as part of the JDK, we do not - // return the factory class here since we do not need to register it ourselves. - return null; - } -} diff --git a/java/broker/src/org/apache/qpid/server/security/auth/JCAProvider.java b/java/broker/src/org/apache/qpid/server/security/auth/JCAProvider.java deleted file mode 100644 index f69e5dc708..0000000000 --- a/java/broker/src/org/apache/qpid/server/security/auth/JCAProvider.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.security.auth; - -import javax.security.sasl.SaslServerFactory; -import java.security.Provider; -import java.security.Security; -import java.util.Map; - -public final class JCAProvider extends Provider -{ - public JCAProvider(Map> providerMap) - { - super("AMQSASLProvider", 1.0, "A JCA provider that registers all " + - "AMQ SASL providers that want to be registered"); - register(providerMap); - Security.addProvider(this); - } - - private void register(Map> providerMap) - { - for (Map.Entry> me : - providerMap.entrySet()) - { - put("SaslServerFactory." + me.getKey(), me.getValue().getName()); - } - } -} \ No newline at end of file diff --git a/java/broker/src/org/apache/qpid/server/security/auth/NullAuthenticationManager.java b/java/broker/src/org/apache/qpid/server/security/auth/NullAuthenticationManager.java deleted file mode 100644 index 14cce86715..0000000000 --- a/java/broker/src/org/apache/qpid/server/security/auth/NullAuthenticationManager.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.security.auth; - -import org.apache.qpid.server.security.auth.AuthenticationManager; -import org.apache.qpid.server.security.auth.AuthenticationResult; - -import javax.security.sasl.SaslException; -import javax.security.sasl.SaslServer; - -public class NullAuthenticationManager implements AuthenticationManager -{ - public String getMechanisms() - { - return "PLAIN"; - } - - public SaslServer createSaslServer(String mechanism, String localFQDN) throws SaslException - { - return new SaslServer() - { - public String getMechanismName() - { - return "PLAIN"; - } - - public byte[] evaluateResponse(byte[] response) throws SaslException - { - return new byte[0]; - } - - public boolean isComplete() - { - return true; - } - - public String getAuthorizationID() - { - return "guest"; - } - - public byte[] unwrap(byte[] incoming, int offset, int len) throws SaslException - { - return new byte[0]; - } - - public byte[] wrap(byte[] outgoing, int offset, int len) throws SaslException - { - return new byte[0]; - } - - public Object getNegotiatedProperty(String propName) - { - return null; - } - - public void dispose() throws SaslException - { - } - }; - } - - public AuthenticationResult authenticate(SaslServer server, byte[] response) - { - return new AuthenticationResult(AuthenticationResult.AuthenticationStatus.SUCCESS); - } -} diff --git a/java/broker/src/org/apache/qpid/server/security/auth/PasswordFilePrincipalDatabase.java b/java/broker/src/org/apache/qpid/server/security/auth/PasswordFilePrincipalDatabase.java deleted file mode 100644 index fb2ac612b6..0000000000 --- a/java/broker/src/org/apache/qpid/server/security/auth/PasswordFilePrincipalDatabase.java +++ /dev/null @@ -1,133 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.security.auth; - -import org.apache.log4j.Logger; - -import javax.security.auth.callback.PasswordCallback; -import javax.security.auth.login.AccountNotFoundException; -import java.security.Principal; -import java.io.*; -import java.util.regex.Pattern; - -/** - * Represents a user database where the account information is stored in a simple flat file. - * - * The file is expected to be in the form: - * username:password - * username1:password1 - * ... - * usernamen:passwordn - * - * where a carriage return separates each username/password pair. Passwords are assumed to be in - * plain text. - * - */ -public class PasswordFilePrincipalDatabase implements PrincipalDatabase -{ - private static final Logger _logger = Logger.getLogger(PasswordFilePrincipalDatabase.class); - - private File _passwordFile; - - private Pattern _regexp = Pattern.compile(":"); - - public PasswordFilePrincipalDatabase() - { - } - - public void setPasswordFile(String passwordFile) throws FileNotFoundException - { - File f = new File(passwordFile); - _logger.info("PasswordFilePrincipalDatabase using file " + f.getAbsolutePath()); - _passwordFile = f; - if (!f.exists()) - { - throw new FileNotFoundException("Cannot find password file " + f); - } - if (!f.canRead()) - { - throw new FileNotFoundException("Cannot read password file " + f + - ". Check permissions."); - } - } - - public void setPassword(Principal principal, PasswordCallback callback) throws IOException, - AccountNotFoundException - { - if (_passwordFile == null) - { - throw new AccountNotFoundException("Unable to locate principal since no password file was specified during initialisation"); - } - if (principal == null) - { - throw new IllegalArgumentException("principal must not be null"); - } - char[] pwd = lookupPassword(principal.getName()); - if (pwd != null) - { - callback.setPassword(pwd); - } - else - { - throw new AccountNotFoundException("No account found for principal " + principal); - } - } - - /** - * Looks up the password for a specified user in the password file. - * Note this code is not secure since it creates strings of passwords. It should be modified - * to create only char arrays which get nulled out. - * @param name - * @return - * @throws IOException - */ - private char[] lookupPassword(String name) throws IOException - { - BufferedReader reader = null; - try - { - reader = new BufferedReader(new FileReader(_passwordFile)); - String line; - - while ((line = reader.readLine()) != null) - { - String[] result = _regexp.split(line); - if (result == null || result.length < 2) - { - continue; - } - - if (name.equals(result[0])) - { - return result[1].toCharArray(); - } - } - return null; - } - finally - { - if (reader != null) - { - reader.close(); - } - } - } -} diff --git a/java/broker/src/org/apache/qpid/server/security/auth/PrincipalDatabase.java b/java/broker/src/org/apache/qpid/server/security/auth/PrincipalDatabase.java deleted file mode 100644 index d7fe21735f..0000000000 --- a/java/broker/src/org/apache/qpid/server/security/auth/PrincipalDatabase.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.security.auth; - -import javax.security.auth.callback.PasswordCallback; -import javax.security.auth.login.AccountNotFoundException; -import java.security.Principal; -import java.io.IOException; - -/** - * Represents a "user database" which is really a way of storing principals (i.e. usernames) and - * passwords. - */ -public interface PrincipalDatabase -{ - /** - * Set the password for a given principal in the specified callback. This is used for certain - * SASL providers. The user database implementation should look up the password in any way it - * chooses and set it in the callback by calling its setPassword method. - * @param principal the principal - * @param callback the password callback that wants to receive the password - * @throws AccountNotFoundException if the account for specified principal could not be found - * @throws IOException if there was an error looking up the principal - */ - void setPassword(Principal principal, PasswordCallback callback) - throws IOException, AccountNotFoundException; -} diff --git a/java/broker/src/org/apache/qpid/server/security/auth/SASLAuthenticationManager.java b/java/broker/src/org/apache/qpid/server/security/auth/SASLAuthenticationManager.java deleted file mode 100644 index 21eb80c69d..0000000000 --- a/java/broker/src/org/apache/qpid/server/security/auth/SASLAuthenticationManager.java +++ /dev/null @@ -1,227 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.security.auth; - -import org.apache.commons.configuration.Configuration; -import org.apache.log4j.Logger; -import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.configuration.PropertyUtils; - -import javax.security.auth.callback.CallbackHandler; -import javax.security.sasl.Sasl; -import javax.security.sasl.SaslException; -import javax.security.sasl.SaslServer; -import javax.security.sasl.SaslServerFactory; -import java.lang.reflect.Method; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.TreeMap; -import java.security.Security; - -public class SASLAuthenticationManager implements AuthenticationManager -{ - private static final Logger _log = Logger.getLogger(SASLAuthenticationManager.class); - - /** - * The list of mechanisms, in the order in which they are configured (i.e. preferred order) - */ - private String _mechanisms; - - /** - * Maps from the mechanism to the callback handler to use for handling those requests - */ - private Map _callbackHandlerMap = new HashMap(); - - /** - * Maps from the mechanism to the properties used to initialise the server. See the method - * Sasl.createSaslServer for details of the use of these properties. This map is populated during initialisation - * of each provider. - */ - private Map> _serverCreationProperties = new HashMap>(); - - public SASLAuthenticationManager() throws Exception - { - _log.info("Initialising SASL authentication manager"); - Map databases = initialisePrincipalDatabases(); - initialiseAuthenticationMechanisms(databases); - } - - private Map initialisePrincipalDatabases() throws Exception - { - Configuration config = ApplicationRegistry.getInstance().getConfiguration(); - List databaseNames = config.getList("security.principal-databases.principal-database.name"); - List databaseClasses = config.getList("security.principal-databases.principal-database.class"); - Map databases = new HashMap(); - for (int i = 0; i < databaseNames.size(); i++) - { - Object o; - try - { - o = Class.forName(databaseClasses.get(i)).newInstance(); - } - catch (Exception e) - { - throw new Exception("Error initialising principal database: " + e, e); - } - - if (!(o instanceof PrincipalDatabase)) - { - throw new Exception("Principal databases must implement the PrincipalDatabase interface"); - } - - initialisePrincipalDatabase((PrincipalDatabase) o, config, i); - - String name = databaseNames.get(i); - if (name == null || name.length() == 0) - { - throw new Exception("Principal database names must have length greater than or equal to one character"); - } - PrincipalDatabase pd = databases.get(name); - if (pd != null) - { - throw new Exception("Duplicate principal database name provided"); - } - _log.info("Initialised principal database " + name + " successfully"); - databases.put(name, (PrincipalDatabase) o); - } - return databases; - } - - private void initialisePrincipalDatabase(PrincipalDatabase principalDatabase, Configuration config, int index) - throws Exception - { - String baseName = "security.principal-databases.principal-database(" + index + ").attributes.attribute."; - List argumentNames = config.getList(baseName + "name"); - List argumentValues = config.getList(baseName + "value"); - for (int i = 0; i < argumentNames.size(); i++) - { - String argName = argumentNames.get(i); - if (argName == null || argName.length() == 0) - { - throw new Exception("Argument names must have length >= 1 character"); - } - if (Character.isLowerCase(argName.charAt(0))) - { - argName = Character.toUpperCase(argName.charAt(0)) + argName.substring(1); - } - String methodName = "set" + argName; - Method method = principalDatabase.getClass().getMethod(methodName, String.class); - if (method == null) - { - throw new Exception("No method " + methodName + " found in class " + principalDatabase.getClass() + - " hence unable to configure principal database. The method must be public and " + - "have a single String argument with a void return type"); - } - method.invoke(principalDatabase, PropertyUtils.replaceProperties(argumentValues.get(i))); - } - } - - private void initialiseAuthenticationMechanisms(Map databases) throws Exception - { - Configuration config = ApplicationRegistry.getInstance().getConfiguration(); - List mechanisms = config.getList("security.sasl.mechanisms.mechanism.initialiser.class"); - - // Maps from the mechanism to the properties used to initialise the server. See the method - // Sasl.createSaslServer for details of the use of these properties. This map is populated during initialisation - // of each provider. - Map> providerMap = new TreeMap>(); - - for (int i = 0; i < mechanisms.size(); i++) - { - String baseName = "security.sasl.mechanisms.mechanism(" + i + ").initialiser"; - String clazz = config.getString(baseName + ".class"); - initialiseAuthenticationMechanism(baseName, clazz, databases, config, providerMap); - } - if (providerMap.size() > 0) - { - Security.addProvider(new JCAProvider(providerMap)); - } - } - - private void initialiseAuthenticationMechanism(String baseName, String clazz, - Map databases, - Configuration configuration, - Map> providerMap) - throws Exception - { - Class initialiserClazz = Class.forName(clazz); - Object o = initialiserClazz.newInstance(); - if (!(o instanceof AuthenticationProviderInitialiser)) - { - throw new Exception("The class " + clazz + " must be an instance of " + - AuthenticationProviderInitialiser.class); - } - AuthenticationProviderInitialiser initialiser = (AuthenticationProviderInitialiser) o; - initialiser.initialise(baseName, configuration, databases); - String mechanism = initialiser.getMechanismName(); - if (_mechanisms == null) - { - _mechanisms = mechanism; - } - else - { - // simple append should be fine since the number of mechanisms is small and this is a one time initialisation - _mechanisms = _mechanisms + " " + mechanism; - } - _callbackHandlerMap.put(mechanism, initialiser.getCallbackHandler()); - _serverCreationProperties.put(mechanism, initialiser.getProperties()); - Class factory = initialiser.getServerFactoryClassForJCARegistration(); - if (factory != null) - { - providerMap.put(mechanism, factory); - } - _log.info("Initialised " + mechanism + " SASL provider successfully"); - } - - public String getMechanisms() - { - return _mechanisms; - } - - public SaslServer createSaslServer(String mechanism, String localFQDN) throws SaslException - { - return Sasl.createSaslServer(mechanism, "AMQP", localFQDN, _serverCreationProperties.get(mechanism), - _callbackHandlerMap.get(mechanism)); - } - - public AuthenticationResult authenticate(SaslServer server, byte[] response) - { - try - { - // Process response from the client - byte[] challenge = server.evaluateResponse(response != null ? response : new byte[0]); - - if (server.isComplete()) - { - return new AuthenticationResult(challenge, AuthenticationResult.AuthenticationStatus.SUCCESS); - } - else - { - return new AuthenticationResult(challenge, AuthenticationResult.AuthenticationStatus.CONTINUE); - } - } - catch (SaslException e) - { - return new AuthenticationResult(AuthenticationResult.AuthenticationStatus.ERROR); - } - } -} diff --git a/java/broker/src/org/apache/qpid/server/security/auth/UsernamePasswordInitialiser.java b/java/broker/src/org/apache/qpid/server/security/auth/UsernamePasswordInitialiser.java deleted file mode 100644 index fccb881eaa..0000000000 --- a/java/broker/src/org/apache/qpid/server/security/auth/UsernamePasswordInitialiser.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.security.auth; - -import org.apache.commons.configuration.Configuration; - -import javax.security.auth.callback.*; -import javax.security.auth.login.AccountNotFoundException; -import javax.security.sasl.AuthorizeCallback; -import java.util.Map; -import java.io.IOException; -import java.security.Principal; - -public abstract class UsernamePasswordInitialiser implements AuthenticationProviderInitialiser -{ - private ServerCallbackHandler _callbackHandler; - - private class ServerCallbackHandler implements CallbackHandler - { - private final PrincipalDatabase _principalDatabase; - - protected ServerCallbackHandler(PrincipalDatabase database) - { - _principalDatabase = database; - } - - public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException - { - Principal username = null; - for (Callback callback : callbacks) - { - if (callback instanceof NameCallback) - { - username = new UsernamePrincipal(((NameCallback)callback).getDefaultName()); - } - else if (callback instanceof PasswordCallback) - { - try - { - _principalDatabase.setPassword(username, (PasswordCallback) callback); - } - catch (AccountNotFoundException e) - { - // very annoyingly the callback handler does not throw anything more appropriate than - // IOException - throw new IOException("Error looking up user " + e); - } - } - else if (callback instanceof AuthorizeCallback) - { - ((AuthorizeCallback)callback).setAuthorized(true); - } - else - { - throw new UnsupportedCallbackException(callback); - } - } - } - } - - public void initialise(String baseConfigPath, Configuration configuration, - Map principalDatabases) throws Exception - { - String principalDatabaseName = configuration.getString(baseConfigPath + ".principal-database"); - PrincipalDatabase db = principalDatabases.get(principalDatabaseName); - if (db == null) - { - throw new Exception("Principal database " + principalDatabaseName + " not found. Ensure the name matches " + - "an entry in the configuration file"); - } - _callbackHandler = new ServerCallbackHandler(db); - } - - public CallbackHandler getCallbackHandler() - { - return _callbackHandler; - } - - public Map getProperties() - { - // there are no properties required for the CRAM-MD5 implementation - return null; - } -} diff --git a/java/broker/src/org/apache/qpid/server/security/auth/UsernamePrincipal.java b/java/broker/src/org/apache/qpid/server/security/auth/UsernamePrincipal.java deleted file mode 100644 index e068ba6fe4..0000000000 --- a/java/broker/src/org/apache/qpid/server/security/auth/UsernamePrincipal.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.security.auth; - -import java.security.Principal; - -/** - * A principal that is just a wrapper for a simple username. - * - */ -public class UsernamePrincipal implements Principal -{ - private String _name; - - public UsernamePrincipal(String name) - { - _name = name; - } - - public String getName() - { - return _name; - } -} diff --git a/java/broker/src/org/apache/qpid/server/security/auth/amqplain/AmqPlainInitialiser.java b/java/broker/src/org/apache/qpid/server/security/auth/amqplain/AmqPlainInitialiser.java deleted file mode 100644 index 1d5932ca31..0000000000 --- a/java/broker/src/org/apache/qpid/server/security/auth/amqplain/AmqPlainInitialiser.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.security.auth.amqplain; - -import org.apache.qpid.server.security.auth.UsernamePasswordInitialiser; - -import javax.security.sasl.SaslServerFactory; - -public class AmqPlainInitialiser extends UsernamePasswordInitialiser -{ - public String getMechanismName() - { - return "AMQPLAIN"; - } - - public Class getServerFactoryClassForJCARegistration() - { - return AmqPlainSaslServerFactory.class; - } -} diff --git a/java/broker/src/org/apache/qpid/server/security/auth/amqplain/AmqPlainSaslServer.java b/java/broker/src/org/apache/qpid/server/security/auth/amqplain/AmqPlainSaslServer.java deleted file mode 100644 index 3ad74ce180..0000000000 --- a/java/broker/src/org/apache/qpid/server/security/auth/amqplain/AmqPlainSaslServer.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.security.auth.amqplain; - -import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.framing.AMQFrameDecodingException; -import org.apache.mina.common.ByteBuffer; - -import javax.security.sasl.SaslServer; -import javax.security.sasl.SaslException; -import javax.security.sasl.AuthorizeCallback; -import javax.security.auth.callback.*; -import java.io.IOException; - -public class AmqPlainSaslServer implements SaslServer -{ - public static final String MECHANISM = "AMQPLAIN"; - - private CallbackHandler _cbh; - - private String _authorizationId; - - private boolean _complete = false; - - public AmqPlainSaslServer(CallbackHandler cbh) - { - _cbh = cbh; - } - - public String getMechanismName() - { - return MECHANISM; - } - - public byte[] evaluateResponse(byte[] response) throws SaslException - { - try - { - final FieldTable ft = new FieldTable(ByteBuffer.wrap(response), response.length); - String username = (String) ft.get("LOGIN"); - // we do not care about the prompt but it throws if null - NameCallback nameCb = new NameCallback("prompt", username); - // we do not care about the prompt but it throws if null - PasswordCallback passwordCb = new PasswordCallback("prompt", false); - // TODO: should not get pwd as a String but as a char array... - String pwd = (String) ft.get("PASSWORD"); - passwordCb.setPassword(pwd.toCharArray()); - AuthorizeCallback authzCb = new AuthorizeCallback(username, username); - Callback[] callbacks = new Callback[]{nameCb, passwordCb, authzCb}; - _cbh.handle(callbacks); - _complete = true; - if (authzCb.isAuthorized()) - { - _authorizationId = authzCb.getAuthenticationID(); - return null; - } - else - { - throw new SaslException("Authentication failed"); - } - } - catch (AMQFrameDecodingException e) - { - throw new SaslException("Unable to decode response: " + e, e); - } - catch (IOException e) - { - throw new SaslException("Error processing data: " + e, e); - } - catch (UnsupportedCallbackException e) - { - throw new SaslException("Unable to obtain data from callback handler: " + e, e); - } - } - - public boolean isComplete() - { - return _complete; - } - - public String getAuthorizationID() - { - return _authorizationId; - } - - public byte[] unwrap(byte[] incoming, int offset, int len) throws SaslException - { - throw new SaslException("Unsupported operation"); - } - - public byte[] wrap(byte[] outgoing, int offset, int len) throws SaslException - { - throw new SaslException("Unsupported operation"); - } - - public Object getNegotiatedProperty(String propName) - { - return null; - } - - public void dispose() throws SaslException - { - _cbh = null; - } -} diff --git a/java/broker/src/org/apache/qpid/server/security/auth/amqplain/AmqPlainSaslServerFactory.java b/java/broker/src/org/apache/qpid/server/security/auth/amqplain/AmqPlainSaslServerFactory.java deleted file mode 100644 index befd724b33..0000000000 --- a/java/broker/src/org/apache/qpid/server/security/auth/amqplain/AmqPlainSaslServerFactory.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.security.auth.amqplain; - -import javax.security.sasl.SaslServerFactory; -import javax.security.sasl.SaslServer; -import javax.security.sasl.SaslException; -import javax.security.sasl.Sasl; -import javax.security.auth.callback.CallbackHandler; -import java.util.Map; - -public class AmqPlainSaslServerFactory implements SaslServerFactory -{ - public SaslServer createSaslServer(String mechanism, String protocol, String serverName, Map props, - CallbackHandler cbh) throws SaslException - { - if (AmqPlainSaslServer.MECHANISM.equals(mechanism)) - { - return new AmqPlainSaslServer(cbh); - } - else - { - 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[]{AmqPlainSaslServer.MECHANISM}; - } - } -} diff --git a/java/broker/src/org/apache/qpid/server/security/auth/plain/PlainInitialiser.java b/java/broker/src/org/apache/qpid/server/security/auth/plain/PlainInitialiser.java deleted file mode 100644 index b92e0b9209..0000000000 --- a/java/broker/src/org/apache/qpid/server/security/auth/plain/PlainInitialiser.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.security.auth.plain; - -import org.apache.qpid.server.security.auth.UsernamePasswordInitialiser; - -import javax.security.sasl.SaslServerFactory; - -public class PlainInitialiser extends UsernamePasswordInitialiser -{ - public String getMechanismName() - { - return "PLAIN"; - } - - public Class getServerFactoryClassForJCARegistration() - { - return PlainSaslServerFactory.class; - } -} diff --git a/java/broker/src/org/apache/qpid/server/security/auth/plain/PlainSaslServer.java b/java/broker/src/org/apache/qpid/server/security/auth/plain/PlainSaslServer.java deleted file mode 100644 index fdf655c2d9..0000000000 --- a/java/broker/src/org/apache/qpid/server/security/auth/plain/PlainSaslServer.java +++ /dev/null @@ -1,144 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.security.auth.plain; - -import javax.security.auth.callback.*; -import javax.security.sasl.AuthorizeCallback; -import javax.security.sasl.SaslException; -import javax.security.sasl.SaslServer; -import java.io.IOException; - -public class PlainSaslServer implements SaslServer -{ - public static final String MECHANISM = "PLAIN"; - - private CallbackHandler _cbh; - - private String _authorizationId; - - private boolean _complete = false; - - public PlainSaslServer(CallbackHandler cbh) - { - _cbh = cbh; - } - - public String getMechanismName() - { - return MECHANISM; - } - - public byte[] evaluateResponse(byte[] response) throws SaslException - { - try - { - int authzidNullPosition = findNullPosition(response, 0); - if (authzidNullPosition < 0) - { - throw new SaslException("Invalid PLAIN encoding, authzid null terminator not found"); - } - int authcidNullPosition = findNullPosition(response, authzidNullPosition + 1); - if (authcidNullPosition < 0) - { - throw new SaslException("Invalid PLAIN encoding, authcid null terminator not found"); - } - - // we do not currently support authcid in any meaningful way - String authcid = new String(response, 0, authzidNullPosition, "utf8"); - String authzid = new String(response, authzidNullPosition + 1, authcidNullPosition - 1, "utf8"); - - // we do not care about the prompt but it throws if null - NameCallback nameCb = new NameCallback("prompt", authzid); - // we do not care about the prompt but it throws if null - PasswordCallback passwordCb = new PasswordCallback("prompt", false); - // TODO: should not get pwd as a String but as a char array... - int passwordLen = response.length - authcidNullPosition - 1; - String pwd = new String(response, authcidNullPosition + 1, passwordLen, "utf8"); - passwordCb.setPassword(pwd.toCharArray()); - AuthorizeCallback authzCb = new AuthorizeCallback(authzid, authzid); - Callback[] callbacks = new Callback[]{nameCb, passwordCb, authzCb}; - _cbh.handle(callbacks); - _complete = true; - if (authzCb.isAuthorized()) - { - _authorizationId = authzCb.getAuthenticationID(); - return null; - } - else - { - throw new SaslException("Authentication failed"); - } - } - catch (IOException e) - { - throw new SaslException("Error processing data: " + e, e); - } - catch (UnsupportedCallbackException e) - { - throw new SaslException("Unable to obtain data from callback handler: " + e, e); - } - } - - private int findNullPosition(byte[] response, int startPosition) - { - int position = startPosition; - while (position < response.length) - { - if (response[position] == (byte) 0) - { - return position; - } - position++; - } - return -1; - } - - public boolean isComplete() - { - return _complete; - } - - public String getAuthorizationID() - { - return _authorizationId; - } - - public byte[] unwrap(byte[] incoming, int offset, int len) throws SaslException - { - throw new SaslException("Unsupported operation"); - } - - public byte[] wrap(byte[] outgoing, int offset, int len) throws SaslException - { - throw new SaslException("Unsupported operation"); - } - - public Object getNegotiatedProperty(String propName) - { - return null; - } - - public void dispose() throws SaslException - { - _cbh = null; - } - -} diff --git a/java/broker/src/org/apache/qpid/server/security/auth/plain/PlainSaslServerFactory.java b/java/broker/src/org/apache/qpid/server/security/auth/plain/PlainSaslServerFactory.java deleted file mode 100644 index 444f7d9b58..0000000000 --- a/java/broker/src/org/apache/qpid/server/security/auth/plain/PlainSaslServerFactory.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.security.auth.plain; - -import javax.security.auth.callback.CallbackHandler; -import javax.security.sasl.Sasl; -import javax.security.sasl.SaslException; -import javax.security.sasl.SaslServer; -import javax.security.sasl.SaslServerFactory; -import java.util.Map; - -public class PlainSaslServerFactory implements SaslServerFactory -{ - public SaslServer createSaslServer(String mechanism, String protocol, String serverName, Map props, - CallbackHandler cbh) throws SaslException - { - if (PlainSaslServer.MECHANISM.equals(mechanism)) - { - return new PlainSaslServer(cbh); - } - else - { - 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[]{PlainSaslServer.MECHANISM}; - } - } -} diff --git a/java/broker/src/org/apache/qpid/server/state/AMQState.java b/java/broker/src/org/apache/qpid/server/state/AMQState.java deleted file mode 100644 index f427cc7206..0000000000 --- a/java/broker/src/org/apache/qpid/server/state/AMQState.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.state; - -/** - * States used in the AMQ protocol. Used by the finite state machine to determine - * valid responses. - */ -public enum AMQState -{ - CONNECTION_NOT_STARTED, - CONNECTION_NOT_AUTH, - CONNECTION_NOT_TUNED, - CONNECTION_NOT_OPENED, - CONNECTION_OPEN, - CONNECTION_CLOSING, - CONNECTION_CLOSED -} diff --git a/java/broker/src/org/apache/qpid/server/state/AMQStateManager.java b/java/broker/src/org/apache/qpid/server/state/AMQStateManager.java deleted file mode 100644 index 5e88ff7f2d..0000000000 --- a/java/broker/src/org/apache/qpid/server/state/AMQStateManager.java +++ /dev/null @@ -1,222 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.state; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.*; -import org.apache.qpid.server.exchange.ExchangeRegistry; -import org.apache.qpid.server.handler.*; -import org.apache.qpid.server.protocol.AMQMethodEvent; -import org.apache.qpid.server.protocol.AMQMethodListener; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.queue.QueueRegistry; -import org.apache.log4j.Logger; - -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.CopyOnWriteArraySet; - -/** - * The state manager is responsible for managing the state of the protocol session. - *

      - * For each AMQProtocolHandler there is a separate state manager. - * - */ -public class AMQStateManager implements AMQMethodListener -{ - private static final Logger _logger = Logger.getLogger(AMQStateManager.class); - - /** - * 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. - */ - private final Map, StateAwareMethodListener>> _state2HandlersMap = - new HashMap, StateAwareMethodListener>>(); - - private CopyOnWriteArraySet _stateListeners = new CopyOnWriteArraySet(); - - public AMQStateManager() - { - this(AMQState.CONNECTION_NOT_STARTED, true); - } - - protected AMQStateManager(AMQState initial, boolean register) - { - _currentState = initial; - if (register) - { - registerListeners(); - } - } - - protected void registerListeners() - { - Map, StateAwareMethodListener> frame2handlerMap = - new HashMap, StateAwareMethodListener>(); - - // 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, StateAwareMethodListener>(); - frame2handlerMap.put(ConnectionStartOkBody.class, ConnectionStartOkMethodHandler.getInstance()); - _state2HandlersMap.put(AMQState.CONNECTION_NOT_STARTED, frame2handlerMap); - - frame2handlerMap = new HashMap, StateAwareMethodListener>(); - frame2handlerMap.put(ConnectionSecureOkBody.class, ConnectionSecureOkMethodHandler.getInstance()); - _state2HandlersMap.put(AMQState.CONNECTION_NOT_AUTH, frame2handlerMap); - - frame2handlerMap = new HashMap, StateAwareMethodListener>(); - frame2handlerMap.put(ConnectionTuneOkBody.class, ConnectionTuneOkMethodHandler.getInstance()); - _state2HandlersMap.put(AMQState.CONNECTION_NOT_TUNED, frame2handlerMap); - - frame2handlerMap = new HashMap, StateAwareMethodListener>(); - frame2handlerMap.put(ConnectionOpenBody.class, ConnectionOpenMethodHandler.getInstance()); - _state2HandlersMap.put(AMQState.CONNECTION_NOT_OPENED, frame2handlerMap); - - // - // ConnectionOpen handlers - // - frame2handlerMap = new HashMap, StateAwareMethodListener>(); - frame2handlerMap.put(ChannelOpenBody.class, ChannelOpenHandler.getInstance()); - frame2handlerMap.put(ChannelCloseBody.class, ChannelCloseHandler.getInstance()); - frame2handlerMap.put(ChannelCloseOkBody.class, ChannelCloseOkHandler.getInstance()); - frame2handlerMap.put(ConnectionCloseBody.class, ConnectionCloseMethodHandler.getInstance()); - frame2handlerMap.put(ExchangeDeclareBody.class, ExchangeDeclareHandler.getInstance()); - frame2handlerMap.put(ExchangeDeleteBody.class, ExchangeDeleteHandler.getInstance()); - frame2handlerMap.put(BasicAckBody.class, BasicAckMethodHandler.getInstance()); - frame2handlerMap.put(BasicRecoverBody.class, BasicRecoverMethodHandler.getInstance()); - frame2handlerMap.put(BasicConsumeBody.class, BasicConsumeMethodHandler.getInstance()); - frame2handlerMap.put(BasicCancelBody.class, BasicCancelMethodHandler.getInstance()); - frame2handlerMap.put(BasicPublishBody.class, BasicPublishMethodHandler.getInstance()); - frame2handlerMap.put(BasicQosBody.class, BasicQosHandler.getInstance()); - frame2handlerMap.put(QueueBindBody.class, QueueBindHandler.getInstance()); - frame2handlerMap.put(QueueDeclareBody.class, QueueDeclareHandler.getInstance()); - frame2handlerMap.put(QueueDeleteBody.class, QueueDeleteHandler.getInstance()); - frame2handlerMap.put(ChannelFlowBody.class, ChannelFlowHandler.getInstance()); - frame2handlerMap.put(TxSelectBody.class, TxSelectHandler.getInstance()); - frame2handlerMap.put(TxCommitBody.class, TxCommitHandler.getInstance()); - frame2handlerMap.put(TxRollbackBody.class, TxRollbackHandler.getInstance()); - - _state2HandlersMap.put(AMQState.CONNECTION_OPEN, frame2handlerMap); - - frame2handlerMap = new HashMap, StateAwareMethodListener>(); - frame2handlerMap.put(ConnectionCloseOkBody.class, ConnectionCloseOkMethodHandler.getInstance()); - _state2HandlersMap.put(AMQState.CONNECTION_CLOSING, frame2handlerMap); - - } - - public AMQState getCurrentState() - { - return _currentState; - } - - public void changeState(AMQState newState) throws AMQException - { - _logger.debug("State changing to " + newState + " from old state " + _currentState); - final AMQState oldState = _currentState; - _currentState = newState; - - for (StateListener l : _stateListeners) - { - l.stateChanged(oldState, newState); - } - } - - public void error(AMQException e) - { - _logger.error("State manager received error notification: " + e, e); - for (StateListener l : _stateListeners) - { - l.error(e); - } - } - - public boolean methodReceived(AMQMethodEvent evt, - AMQProtocolSession protocolSession, - QueueRegistry queueRegistry, - ExchangeRegistry exchangeRegistry) throws AMQException - { - StateAwareMethodListener handler = findStateTransitionHandler(_currentState, evt.getMethod()); - if (handler != null) - { - handler.methodReceived(this, queueRegistry, exchangeRegistry, protocolSession, evt); - return true; - } - return false; - } - - protected StateAwareMethodListener findStateTransitionHandler(AMQState currentState, - B frame) - throws IllegalStateTransitionException - { - if (_logger.isDebugEnabled()) - { - _logger.debug("Looking for state transition handler for frame " + frame.getClass()); - } - final Map, StateAwareMethodListener> - classToHandlerMap = _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(frame.getClass()); - 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 addStateListener(StateListener listener) - { - _logger.debug("Adding state listener"); - _stateListeners.add(listener); - } - - public void removeStateListener(StateListener listener) - { - _stateListeners.remove(listener); - } -} diff --git a/java/broker/src/org/apache/qpid/server/state/IllegalStateTransitionException.java b/java/broker/src/org/apache/qpid/server/state/IllegalStateTransitionException.java deleted file mode 100644 index 2d7cc27a85..0000000000 --- a/java/broker/src/org/apache/qpid/server/state/IllegalStateTransitionException.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.state; - -import org.apache.qpid.AMQException; - -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/java/broker/src/org/apache/qpid/server/state/StateAwareMethodListener.java b/java/broker/src/org/apache/qpid/server/state/StateAwareMethodListener.java deleted file mode 100644 index 7d58f242e5..0000000000 --- a/java/broker/src/org/apache/qpid/server/state/StateAwareMethodListener.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.state; - -import org.apache.qpid.AMQException; -import org.apache.qpid.server.protocol.AMQMethodEvent; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.queue.QueueRegistry; -import org.apache.qpid.server.exchange.ExchangeRegistry; -import org.apache.qpid.framing.AMQMethodBody; - -/** - * A frame listener that is informed of the protocol state when invoked and has - * the opportunity to update state. - * - */ -public interface StateAwareMethodListener -{ - void methodReceived(AMQStateManager stateManager, QueueRegistry queueRegistry, - ExchangeRegistry exchangeRegistry, AMQProtocolSession protocolSession, - AMQMethodEvent evt) throws AMQException; -} diff --git a/java/broker/src/org/apache/qpid/server/state/StateListener.java b/java/broker/src/org/apache/qpid/server/state/StateListener.java deleted file mode 100644 index 00fc09867b..0000000000 --- a/java/broker/src/org/apache/qpid/server/state/StateListener.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.state; - -import org.apache.qpid.AMQException; - -public interface StateListener -{ - void stateChanged(AMQState oldState, AMQState newState) throws AMQException; - - void error(Throwable t); -} diff --git a/java/broker/src/org/apache/qpid/server/store/MemoryMessageStore.java b/java/broker/src/org/apache/qpid/server/store/MemoryMessageStore.java deleted file mode 100644 index 328aed81d9..0000000000 --- a/java/broker/src/org/apache/qpid/server/store/MemoryMessageStore.java +++ /dev/null @@ -1,145 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.store; - -import org.apache.commons.configuration.Configuration; -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; -import org.apache.qpid.server.queue.AMQMessage; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.queue.QueueRegistry; - -import java.util.List; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.atomic.AtomicLong; - -/** - * A simple message store that stores the messages in a threadsafe structure in memory. - */ -public class MemoryMessageStore implements MessageStore -{ - private static final Logger _log = Logger.getLogger(MemoryMessageStore.class); - - private static final int DEFAULT_HASHTABLE_CAPACITY = 50000; - - private static final String HASHTABLE_CAPACITY_CONFIG = "hashtable-capacity"; - - protected ConcurrentMap _messageMap; - - private final AtomicLong _messageId = new AtomicLong(1); - - public void configure() - { - _log.info("Using capacity " + DEFAULT_HASHTABLE_CAPACITY + " for hash table"); - _messageMap = new ConcurrentHashMap(DEFAULT_HASHTABLE_CAPACITY); - } - - public void configure(String base, Configuration config) - { - int hashtableCapacity = config.getInt(base + "." + HASHTABLE_CAPACITY_CONFIG, DEFAULT_HASHTABLE_CAPACITY); - _log.info("Using capacity " + hashtableCapacity + " for hash table"); - _messageMap = new ConcurrentHashMap(hashtableCapacity); - } - - public void configure(QueueRegistry queueRegistry, String base, Configuration config) throws Exception - { - configure(base, config); - } - - public void close() throws Exception - { - if (_messageMap != null) - { - _messageMap.clear(); - _messageMap = null; - } - } - - public void put(AMQMessage msg) - { - _messageMap.put(msg.getMessageId(), msg); - } - - public void removeMessage(long messageId) - { - if (_log.isDebugEnabled()) - { - _log.debug("Removing message with id " + messageId); - } - _messageMap.remove(messageId); - } - - public void createQueue(AMQQueue queue) throws AMQException - { - //To change body of implemented methods use File | Settings | File Templates. - } - - public void removeQueue(String name) throws AMQException - { - //To change body of implemented methods use File | Settings | File Templates. - } - - public void enqueueMessage(String name, long messageId) throws AMQException - { - //To change body of implemented methods use File | Settings | File Templates. - } - - public void dequeueMessage(String name, long messageId) throws AMQException - { - //To change body of implemented methods use File | Settings | File Templates. - } - - public void beginTran() throws AMQException - { - //To change body of implemented methods use File | Settings | File Templates. - } - - public void commitTran() throws AMQException - { - //To change body of implemented methods use File | Settings | File Templates. - } - - public void abortTran() throws AMQException - { - //To change body of implemented methods use File | Settings | File Templates. - } - - public boolean inTran() - { - return false; - } - - public List createQueues() throws AMQException - { - return null; //To change body of implemented methods use File | Settings | File Templates. - } - - public long getNewMessageId() - { - return _messageId.getAndIncrement(); - } - - public AMQMessage getMessage(long messageId) - { - return _messageMap.get(messageId); - } -} diff --git a/java/broker/src/org/apache/qpid/server/store/MessageStore.java b/java/broker/src/org/apache/qpid/server/store/MessageStore.java deleted file mode 100644 index 8ee1d09862..0000000000 --- a/java/broker/src/org/apache/qpid/server/store/MessageStore.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.store; - -import org.apache.commons.configuration.Configuration; -import org.apache.qpid.AMQException; -import org.apache.qpid.server.queue.AMQMessage; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.queue.QueueRegistry; - -import java.util.List; - -public interface MessageStore -{ - /** - * Called after instantiation in order to configure the message store. A particular implementation can define - * whatever parameters it wants. - * @param queueRegistry the registry of queues to be used by this store - * @param base the base element identifier from which all configuration items are relative. For example, if the base - * element is "store", the all elements used by concrete classes will be "store.foo" etc. - * @param config the apache commons configuration object - */ - void configure(QueueRegistry queueRegistry, String base, Configuration config) throws Exception; - - /** - * Called to close and cleanup any resources used by the message store. - * @throws Exception - */ - void close() throws Exception; - - void put(AMQMessage msg) throws AMQException; - - void removeMessage(long messageId) throws AMQException; - - void createQueue(AMQQueue queue) throws AMQException; - - void removeQueue(String name) throws AMQException; - - void enqueueMessage(String name, long messageId) throws AMQException; - - void dequeueMessage(String name, long messageId) throws AMQException; - - void beginTran() throws AMQException; - - void commitTran() throws AMQException; - - void abortTran() throws AMQException; - - boolean inTran(); - - /** - * Recreate all queues that were persisted, including re-enqueuing of existing messages - * @return - * @throws AMQException - */ - List createQueues() throws AMQException; - - /** - * Return a valid, currently unused message id. - * @return a message id - */ - long getNewMessageId(); -} - - diff --git a/java/broker/src/org/apache/qpid/server/transport/ConnectorConfiguration.java b/java/broker/src/org/apache/qpid/server/transport/ConnectorConfiguration.java deleted file mode 100644 index ca008a0bd5..0000000000 --- a/java/broker/src/org/apache/qpid/server/transport/ConnectorConfiguration.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.transport; - -import org.apache.qpid.configuration.Configured; -import org.apache.mina.common.IoAcceptor; -import org.apache.mina.filter.executor.ExecutorExecutor; -import org.apache.mina.util.NewThreadExecutor; - -public class ConnectorConfiguration -{ - public static final String DEFAULT_PORT = "5672"; - - public static final String SSL_PORT = "8672"; - - @Configured(path = "connector.processors", - defaultValue = "4") - public int processors; - - @Configured(path = "connector.port", - defaultValue = DEFAULT_PORT) - public int port; - - @Configured(path = "connector.bind", - defaultValue = "wildcard") - public String bindAddress; - - @Configured(path = "connector.sslport", - defaultValue = SSL_PORT) - public int sslPort; - - @Configured(path = "connector.socketReceiveBuffer", - defaultValue = "32767") - public int socketReceiveBufferSize; - - @Configured(path = "connector.socketWriteBuffer", - defaultValue = "32767") - public int socketWriteBuferSize; - - @Configured(path = "connector.tcpNoDelay", - defaultValue = "true") - public boolean tcpNoDelay; - - @Configured(path = "advanced.filterchain[@enableExecutorPool]", - defaultValue = "false") - public boolean enableExecutorPool; - - @Configured(path = "advanced.enablePooledAllocator", - defaultValue = "false") - public boolean enablePooledAllocator; - - @Configured(path = "advanced.enableDirectBuffers", - defaultValue = "false") - public boolean enableDirectBuffers; - - @Configured(path = "connector.ssl", - defaultValue = "false") - public boolean enableSSL; - - @Configured(path = "connector.nonssl", - defaultValue = "true") - public boolean enableNonSSL; - - public IoAcceptor createAcceptor() - { - return new org.apache.mina.transport.socket.nio.SocketAcceptor(processors, new NewThreadExecutor()); - } -} diff --git a/java/broker/src/org/apache/qpid/server/transport/ThreadPoolFilter.java b/java/broker/src/org/apache/qpid/server/transport/ThreadPoolFilter.java deleted file mode 100644 index 2ee75c001f..0000000000 --- a/java/broker/src/org/apache/qpid/server/transport/ThreadPoolFilter.java +++ /dev/null @@ -1,695 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.transport; - -import org.apache.mina.common.*; -import org.apache.mina.util.*; -import org.apache.mina.util.Queue; -import org.apache.mina.util.Stack; - -import java.util.*; - -/** - * A Thread-pooling filter. This filter forwards {@link IoHandler} events - * to its thread pool. - *

      - * This is an implementation of - * Leader/Followers - * thread pool by Douglas C. Schmidt et al. - */ -public class ThreadPoolFilter extends IoFilterAdapter -{ - /** - * Default maximum size of thread pool (2G). - */ - public static final int DEFAULT_MAXIMUM_POOL_SIZE = Integer.MAX_VALUE; - - /** - * Default keep-alive time of thread pool (1 min). - */ - public static final int DEFAULT_KEEP_ALIVE_TIME = 60 * 1000; - - /** - * A queue which contains {@link Integer}s which represents reusable - * thread IDs. {@link Worker} first checks this queue and then - * uses {@link #threadId} when no reusable thread ID is available. - */ - private static final Queue threadIdReuseQueue = new Queue(); - private static int threadId = 0; - - private static int acquireThreadId() - { - synchronized (threadIdReuseQueue) - { - Integer id = (Integer) threadIdReuseQueue.pop(); - if (id == null) - { - return ++ threadId; - } - else - { - return id.intValue(); - } - } - } - - private static void releaseThreadId(int id) - { - synchronized (threadIdReuseQueue) - { - threadIdReuseQueue.push(new Integer(id)); - } - } - - private final String threadNamePrefix; - private final Map buffers = new IdentityHashMap(); - private final BlockingQueue unfetchedSessionBuffers = new BlockingQueue(); - private final Set allSessionBuffers = new IdentityHashSet(); - - private Worker leader; - private final Stack followers = new Stack(); - private final Set allWorkers = new IdentityHashSet(); - - private int maximumPoolSize = DEFAULT_MAXIMUM_POOL_SIZE; - private int keepAliveTime = DEFAULT_KEEP_ALIVE_TIME; - - private boolean shuttingDown; - - private int poolSize; - private final Object poolSizeLock = new Object(); - - /** - * Creates a new instance of this filter with default thread pool settings. - */ - public ThreadPoolFilter() - { - this("IoThreadPool"); - } - - /** - * Creates a new instance of this filter with the specified thread name prefix - * and other default settings. - * - * @param threadNamePrefix the prefix of the thread names this pool will create. - */ - public ThreadPoolFilter(String threadNamePrefix) - { - if (threadNamePrefix == null) - { - throw new NullPointerException("threadNamePrefix"); - } - threadNamePrefix = threadNamePrefix.trim(); - if (threadNamePrefix.length() == 0) - { - throw new IllegalArgumentException("threadNamePrefix is empty."); - } - this.threadNamePrefix = threadNamePrefix; - } - - public String getThreadNamePrefix() - { - return threadNamePrefix; - } - - public int getPoolSize() - { - synchronized (poolSizeLock) - { - return poolSize; - } - } - - public int getMaximumPoolSize() - { - return maximumPoolSize; - } - - public int getKeepAliveTime() - { - return keepAliveTime; - } - - public void setMaximumPoolSize(int maximumPoolSize) - { - if (maximumPoolSize <= 0) - { - throw new IllegalArgumentException(); - } - this.maximumPoolSize = maximumPoolSize; - } - - public void setKeepAliveTime(int keepAliveTime) - { - this.keepAliveTime = keepAliveTime; - } - - public void init() - { - shuttingDown = false; - leader = new Worker(); - leader.start(); - leader.lead(); - } - - public void destroy() - { - shuttingDown = true; - int expectedPoolSize = 0; - while (getPoolSize() != expectedPoolSize) - { - List allWorkers; - synchronized (poolSizeLock) - { - allWorkers = new ArrayList(this.allWorkers); - } - - // You may not interrupt the current thread. - if (allWorkers.remove(Thread.currentThread())) - { - expectedPoolSize = 1; - } - - for (Iterator i = allWorkers.iterator(); i.hasNext();) - { - Worker worker = (Worker) i.next(); - while (worker.isAlive()) - { - worker.interrupt(); - try - { - // This timeout will help us from - // infinite lock-up and interrupt workers again. - worker.join(100); - } - catch (InterruptedException e) - { - } - } - } - } - - this.allSessionBuffers.clear(); - this.unfetchedSessionBuffers.clear(); - this.buffers.clear(); - this.followers.clear(); - this.leader = null; - } - - private void increasePoolSize(Worker worker) - { - synchronized (poolSizeLock) - { - poolSize++; - allWorkers.add(worker); - } - } - - private void decreasePoolSize(Worker worker) - { - synchronized (poolSizeLock) - { - poolSize--; - allWorkers.remove(worker); - } - } - - private void fireEvent(NextFilter nextFilter, IoSession session, - EventType type, Object data) - { - final BlockingQueue unfetchedSessionBuffers = this.unfetchedSessionBuffers; - final Set allSessionBuffers = this.allSessionBuffers; - final Event event = new Event(type, nextFilter, data); - - synchronized (unfetchedSessionBuffers) - { - final SessionBuffer buf = getSessionBuffer(session); - final Queue eventQueue = buf.eventQueue; - - synchronized (buf) - { - eventQueue.push(event); - } - - if (!allSessionBuffers.contains(buf)) - { - allSessionBuffers.add(buf); - unfetchedSessionBuffers.push(buf); - } - } - } - - /** - * Implement this method to fetch (or pop) a {@link SessionBuffer} from - * the given unfetchedSessionBuffers. The default implementation - * simply pops the buffer from it. You could prioritize the fetch order. - * - * @return A non-null {@link SessionBuffer} - */ - protected SessionBuffer fetchSessionBuffer(Queue unfetchedSessionBuffers) - { - return (SessionBuffer) unfetchedSessionBuffers.pop(); - } - - private SessionBuffer getSessionBuffer(IoSession session) - { - final Map buffers = this.buffers; - SessionBuffer buf = (SessionBuffer) buffers.get(session); - if (buf == null) - { - synchronized (buffers) - { - buf = (SessionBuffer) buffers.get(session); - if (buf == null) - { - buf = new SessionBuffer(session); - buffers.put(session, buf); - } - } - } - return buf; - } - - private void removeSessionBuffer(SessionBuffer buf) - { - final Map buffers = this.buffers; - final IoSession session = buf.session; - synchronized (buffers) - { - buffers.remove(session); - } - } - - protected static class SessionBuffer - { - private final IoSession session; - - private final Queue eventQueue = new Queue(); - - private SessionBuffer(IoSession session) - { - this.session = session; - } - - public IoSession getSession() - { - return session; - } - - public Queue getEventQueue() - { - return eventQueue; - } - } - - private class Worker extends Thread - { - private final int id; - private final Object promotionLock = new Object(); - private boolean dead; - - private Worker() - { - int id = acquireThreadId(); - this.id = id; - this.setName(threadNamePrefix + '-' + id); - increasePoolSize(this); - } - - public boolean lead() - { - final Object promotionLock = this.promotionLock; - synchronized (promotionLock) - { - if (dead) - { - return false; - } - - leader = this; - promotionLock.notify(); - } - - return true; - } - - public void run() - { - for (; ;) - { - if (!waitForPromotion()) - { - break; - } - - SessionBuffer buf = fetchBuffer(); - giveUpLead(); - if (buf == null) - { - break; - } - - processEvents(buf); - follow(); - releaseBuffer(buf); - } - - decreasePoolSize(this); - releaseThreadId(id); - } - - private SessionBuffer fetchBuffer() - { - BlockingQueue unfetchedSessionBuffers = ThreadPoolFilter.this.unfetchedSessionBuffers; - synchronized (unfetchedSessionBuffers) - { - while (!shuttingDown) - { - try - { - unfetchedSessionBuffers.waitForNewItem(); - } - catch (InterruptedException e) - { - continue; - } - - return ThreadPoolFilter.this.fetchSessionBuffer(unfetchedSessionBuffers); - } - } - - return null; - } - - private void processEvents(SessionBuffer buf) - { - final IoSession session = buf.session; - final Queue eventQueue = buf.eventQueue; - for (; ;) - { - Event event; - synchronized (buf) - { - event = (Event) eventQueue.pop(); - if (event == null) - { - break; - } - } - processEvent(event.getNextFilter(), session, - event.getType(), event.getData()); - } - } - - private void follow() - { - final Object promotionLock = this.promotionLock; - final Stack followers = ThreadPoolFilter.this.followers; - synchronized (promotionLock) - { - if (this != leader) - { - synchronized (followers) - { - followers.push(this); - } - } - } - } - - private void releaseBuffer(SessionBuffer buf) - { - final BlockingQueue unfetchedSessionBuffers = ThreadPoolFilter.this.unfetchedSessionBuffers; - final Set allSessionBuffers = ThreadPoolFilter.this.allSessionBuffers; - final Queue eventQueue = buf.eventQueue; - - synchronized (unfetchedSessionBuffers) - { - if (eventQueue.isEmpty()) - { - allSessionBuffers.remove(buf); - removeSessionBuffer(buf); - } - else - { - unfetchedSessionBuffers.push(buf); - } - } - } - - private boolean waitForPromotion() - { - final Object promotionLock = this.promotionLock; - - long startTime = System.currentTimeMillis(); - long currentTime = System.currentTimeMillis(); - - synchronized (promotionLock) - { - while (this != leader && !shuttingDown) - { - // Calculate remaining keep-alive time - int keepAliveTime = getKeepAliveTime(); - if (keepAliveTime > 0) - { - keepAliveTime -= (currentTime - startTime); - } - else - { - keepAliveTime = Integer.MAX_VALUE; - } - - // Break the loop if there's no remaining keep-alive time. - if (keepAliveTime <= 0) - { - break; - } - - // Wait for promotion - try - { - promotionLock.wait(keepAliveTime); - } - catch (InterruptedException e) - { - } - - // Update currentTime for the next iteration - currentTime = System.currentTimeMillis(); - } - - boolean timeToLead = this == leader && !shuttingDown; - - if (!timeToLead) - { - // time to die - synchronized (followers) - { - followers.remove(this); - } - - // Mark as dead explicitly when we've got promotionLock. - dead = true; - } - - return timeToLead; - } - } - - private void giveUpLead() - { - final Stack followers = ThreadPoolFilter.this.followers; - Worker worker; - do - { - synchronized (followers) - { - worker = (Worker) followers.pop(); - } - - if (worker == null) - { - // Increase the number of threads if we - // are not shutting down and we can increase the number. - if (!shuttingDown - && getPoolSize() < getMaximumPoolSize()) - { - worker = new Worker(); - worker.lead(); - worker.start(); - } - - // This loop should end because: - // 1) lead() is called already, - // 2) or it is shutting down and there's no more threads left. - break; - } - } - while (!worker.lead()); - } - } - - protected static class EventType - { - public static final EventType OPENED = new EventType("OPENED"); - - public static final EventType CLOSED = new EventType("CLOSED"); - - public static final EventType READ = new EventType("READ"); - - public static final EventType WRITTEN = new EventType("WRITTEN"); - - public static final EventType RECEIVED = new EventType("RECEIVED"); - - public static final EventType SENT = new EventType("SENT"); - - public static final EventType IDLE = new EventType("IDLE"); - - public static final EventType EXCEPTION = new EventType("EXCEPTION"); - - private final String value; - - private EventType(String value) - { - this.value = value; - } - - public String toString() - { - return value; - } - } - - protected static class Event - { - private final EventType type; - private final NextFilter nextFilter; - private final Object data; - - public Event(EventType type, NextFilter nextFilter, Object data) - { - this.type = type; - this.nextFilter = nextFilter; - this.data = data; - } - - public Object getData() - { - return data; - } - - - public NextFilter getNextFilter() - { - return nextFilter; - } - - - public EventType getType() - { - return type; - } - } - - public void sessionCreated(NextFilter nextFilter, IoSession session) - { - nextFilter.sessionCreated(session); - } - - public void sessionOpened(NextFilter nextFilter, - IoSession session) - { - fireEvent(nextFilter, session, EventType.OPENED, null); - } - - public void sessionClosed(NextFilter nextFilter, - IoSession session) - { - fireEvent(nextFilter, session, EventType.CLOSED, null); - } - - public void sessionIdle(NextFilter nextFilter, - IoSession session, IdleStatus status) - { - fireEvent(nextFilter, session, EventType.IDLE, status); - } - - public void exceptionCaught(NextFilter nextFilter, - IoSession session, Throwable cause) - { - fireEvent(nextFilter, session, EventType.EXCEPTION, cause); - } - - public void messageReceived(NextFilter nextFilter, - IoSession session, Object message) - { - ByteBufferUtil.acquireIfPossible(message); - fireEvent(nextFilter, session, EventType.RECEIVED, message); - } - - public void messageSent(NextFilter nextFilter, - IoSession session, Object message) - { - ByteBufferUtil.acquireIfPossible(message); - fireEvent(nextFilter, session, EventType.SENT, message); - } - - protected void processEvent(NextFilter nextFilter, - IoSession session, EventType type, - Object data) - { - if (type == EventType.RECEIVED) - { - nextFilter.messageReceived(session, data); - ByteBufferUtil.releaseIfPossible(data); - } - else if (type == EventType.SENT) - { - nextFilter.messageSent(session, data); - ByteBufferUtil.releaseIfPossible(data); - } - else if (type == EventType.EXCEPTION) - { - nextFilter.exceptionCaught(session, (Throwable) data); - } - else if (type == EventType.IDLE) - { - nextFilter.sessionIdle(session, (IdleStatus) data); - } - else if (type == EventType.OPENED) - { - nextFilter.sessionOpened(session); - } - else if (type == EventType.CLOSED) - { - nextFilter.sessionClosed(session); - } - } - - public void filterWrite(NextFilter nextFilter, IoSession session, WriteRequest writeRequest) - { - nextFilter.filterWrite(session, writeRequest); - } - - public void filterClose(NextFilter nextFilter, IoSession session) throws Exception - { - nextFilter.filterClose(session); - } -} \ No newline at end of file diff --git a/java/broker/src/org/apache/qpid/server/txn/TxnBuffer.java b/java/broker/src/org/apache/qpid/server/txn/TxnBuffer.java deleted file mode 100644 index 402065d5e1..0000000000 --- a/java/broker/src/org/apache/qpid/server/txn/TxnBuffer.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.txn; - -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; -import org.apache.qpid.server.store.MessageStore; - -import java.util.ArrayList; -import java.util.List; - -/** - * Holds a list of TxnOp instance representing transactional - * operations. - */ -public class TxnBuffer -{ - private boolean _containsPersistentChanges = false; - private final MessageStore _store; - private final List _ops = new ArrayList(); - private static final Logger _log = Logger.getLogger(TxnBuffer.class); - - public TxnBuffer(MessageStore store) - { - _store = store; - } - - public void containsPersistentChanges() - { - _containsPersistentChanges = true; - } - - public void commit() throws AMQException - { - if (_containsPersistentChanges) - { - _log.debug("Begin Transaction."); - _store.beginTran(); - if(prepare()) - { - _log.debug("Transaction Succeeded"); - _store.commitTran(); - for (TxnOp op : _ops) - { - op.commit(); - } - } - else - { - _log.debug("Transaction Failed"); - _store.abortTran(); - } - }else{ - if(prepare()) - { - for (TxnOp op : _ops) - { - op.commit(); - } - } - } - _ops.clear(); - } - - private boolean prepare() - { - for (int i = 0; i < _ops.size(); i++) - { - TxnOp op = _ops.get(i); - try - { - op.prepare(); - } - catch(Exception e) - { - //compensate previously prepared ops - for(int j = 0; j < i; j++) - { - _ops.get(j).undoPrepare(); - } - return false; - } - } - return true; - } - - public void rollback() throws AMQException - { - for (TxnOp op : _ops) - { - op.rollback(); - } - _ops.clear(); - } - - public void enlist(TxnOp op) - { - _ops.add(op); - } - - public void cancel(TxnOp op) - { - _ops.remove(op); - } -} diff --git a/java/broker/src/org/apache/qpid/server/txn/TxnOp.java b/java/broker/src/org/apache/qpid/server/txn/TxnOp.java deleted file mode 100644 index e863bab73e..0000000000 --- a/java/broker/src/org/apache/qpid/server/txn/TxnOp.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.txn; - -import org.apache.qpid.AMQException; - -/** - * This provides the abstraction of an individual operation within a - * transaction. It is used by the TxnBuffer class. - */ -public interface TxnOp -{ - /** - * Do the part of the operation that updates persistent state - */ - public void prepare() throws AMQException; - /** - * Complete the operation started by prepare. Can now update in - * memory state or make netork transfers. - */ - public void commit(); - /** - * This is not the same as rollback. Unfortunately the use of an - * in memory reference count as a locking mechanism and a test for - * whether a message should be deleted means that as things are, - * handling an acknowledgement unavoidably alters both memory and - * persistent state on prepare. This is needed to 'compensate' or - * undo the in-memory change if the peristent update of later ops - * fails. - */ - public void undoPrepare(); - /** - * Rolls back the operation. - */ - public void rollback(); -} diff --git a/java/broker/src/org/apache/qpid/server/util/CircularBuffer.java b/java/broker/src/org/apache/qpid/server/util/CircularBuffer.java deleted file mode 100644 index 4767844abe..0000000000 --- a/java/broker/src/org/apache/qpid/server/util/CircularBuffer.java +++ /dev/null @@ -1,126 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.util; - -import java.util.Iterator; - -public class CircularBuffer implements Iterable -{ - private final Object[] _log; - private int _size; - private int _index; - - public CircularBuffer(int size) - { - _log = new Object[size]; - } - - public void add(Object o) - { - _log[_index++] = o; - _size = Math.min(_size+1, _log.length); - if(_index >= _log.length) - { - _index = 0; - } - } - - public Object get(int i) - { - if(i >= _log.length) - { - throw new ArrayIndexOutOfBoundsException(i); - } - return _log[index(i)]; - } - - public int size() { - return _size; - } - - public Iterator iterator() - { - return new Iterator() - { - private int i = 0; - - public boolean hasNext() - { - return i < _size; - } - - public Object next() - { - return get(i++); - } - - public void remove() - { - throw new UnsupportedOperationException(); - } - }; - } - - public String toString() - { - StringBuilder s = new StringBuilder(); - boolean first = true; - for(Object o : this) - { - if(!first) - { - s.append(", "); - } - else - { - first = false; - } - s.append(o); - } - return s.toString(); - } - - public void dump() - { - for(Object o : this) - { - System.out.println(o); - } - } - - int index(int i) - { - return _size == _log.length ? (_index + i) % _log.length : i; - } - - public static void main(String[] artgv) - { - String[] items = new String[]{ - "A","B","C","D","E","F","G","H","I","J","K" - }; - CircularBuffer buffer = new CircularBuffer(5); - for(String s : items) - { - buffer.add(s); - System.out.println(buffer); - } - } -} diff --git a/java/broker/src/org/apache/qpid/server/util/ConcurrentLinkedQueueNoSize.java b/java/broker/src/org/apache/qpid/server/util/ConcurrentLinkedQueueNoSize.java deleted file mode 100644 index cf5e71a6e2..0000000000 --- a/java/broker/src/org/apache/qpid/server/util/ConcurrentLinkedQueueNoSize.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.util; - -import java.util.concurrent.ConcurrentLinkedQueue; - -public class ConcurrentLinkedQueueNoSize extends ConcurrentLinkedQueue -{ - public int size() - { - if (isEmpty()) - { - return 0; - } - else - { - return 1; - } - } -} diff --git a/java/broker/src/org/apache/qpid/server/util/LoggingProxy.java b/java/broker/src/org/apache/qpid/server/util/LoggingProxy.java deleted file mode 100644 index eda97e0ed2..0000000000 --- a/java/broker/src/org/apache/qpid/server/util/LoggingProxy.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.util; - -import java.lang.reflect.InvocationHandler; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.lang.reflect.Proxy; -import java.util.Arrays; - -/** - * Dynamic proxy that records invocations in a fixed size circular buffer, - * dumping details on hitting an exception. - *

      - * Useful in debugging. - *

      - */ -public class LoggingProxy implements InvocationHandler -{ - private final Object _target; - private final CircularBuffer _log; - - public LoggingProxy(Object target, int size) - { - _target = target; - _log = new CircularBuffer(size); - } - - public Object invoke(Object proxy, Method method, Object[] args) throws Throwable - { - try - { - entered(method, args); - Object result = method.invoke(_target, args); - returned(method, result); - return result; - } - catch(InvocationTargetException e) - { - dump(); - throw e.getTargetException(); - } - } - - void dump() - { - _log.dump(); - } - - CircularBuffer getBuffer() - { - return _log; - } - - private synchronized void entered(Method method, Object[] args) - { - if (args == null) - { - _log.add(Thread.currentThread() + ": " + method.getName() + "() entered"); - } - else - { - _log.add(Thread.currentThread() + ": " + method.getName() + "(" + Arrays.toString(args) + ") entered"); - } - } - - private synchronized void returned(Method method, Object result) - { - if (method.getReturnType() == Void.TYPE) - { - _log.add(Thread.currentThread() + ": " + method.getName() + "() returned"); - } - else - { - _log.add(Thread.currentThread() + ": " + method.getName() + "() returned " + result); - } - } - - public Object getProxy(Class... c) - { - return Proxy.newProxyInstance(_target.getClass().getClassLoader(), c, this); - } - - public int getBufferSize() { - return _log.size(); - } -} diff --git a/java/broker/src/org/apache/qpid/server/util/NullApplicationRegistry.java b/java/broker/src/org/apache/qpid/server/util/NullApplicationRegistry.java deleted file mode 100644 index 2e77f33363..0000000000 --- a/java/broker/src/org/apache/qpid/server/util/NullApplicationRegistry.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.util; - -import org.apache.qpid.server.exchange.DefaultExchangeFactory; -import org.apache.qpid.server.exchange.DefaultExchangeRegistry; -import org.apache.qpid.server.exchange.ExchangeFactory; -import org.apache.qpid.server.exchange.ExchangeRegistry; -import org.apache.qpid.server.management.ManagedObjectRegistry; -import org.apache.qpid.server.management.NoopManagedObjectRegistry; -import org.apache.qpid.server.queue.DefaultQueueRegistry; -import org.apache.qpid.server.queue.QueueRegistry; -import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.security.auth.AuthenticationManager; -import org.apache.qpid.server.security.auth.NullAuthenticationManager; -import org.apache.qpid.server.store.MessageStore; -import org.apache.qpid.server.store.MemoryMessageStore; -import org.apache.commons.configuration.Configuration; -import org.apache.commons.configuration.MapConfiguration; - -import java.util.HashMap; - -public class NullApplicationRegistry extends ApplicationRegistry -{ - private QueueRegistry _queueRegistry; - - private ExchangeRegistry _exchangeRegistry; - - private ExchangeFactory _exchangeFactory; - - private ManagedObjectRegistry _managedObjectRegistry; - - private AuthenticationManager _authenticationManager; - - private MessageStore _messageStore; - - - public NullApplicationRegistry() - { - super(new MapConfiguration(new HashMap())); - } - - public void initialise() throws Exception - { - _managedObjectRegistry = new NoopManagedObjectRegistry(); - _queueRegistry = new DefaultQueueRegistry(); - _exchangeFactory = new DefaultExchangeFactory(); - _exchangeRegistry = new DefaultExchangeRegistry(_exchangeFactory); - _authenticationManager = new NullAuthenticationManager(); - _messageStore = new MemoryMessageStore(); - ((MemoryMessageStore)_messageStore).configure(); - - _configuration.addProperty("heartbeat.delay", 10 * 60); // 10 minutes - } - - public Configuration getConfiguration() - { - return _configuration; - } - - public QueueRegistry getQueueRegistry() - { - return _queueRegistry; - } - - public ExchangeRegistry getExchangeRegistry() - { - return _exchangeRegistry; - } - - public ExchangeFactory getExchangeFactory() - { - return _exchangeFactory; - } - - public ManagedObjectRegistry getManagedObjectRegistry() - { - return _managedObjectRegistry; - } - - public AuthenticationManager getAuthenticationManager() - { - return _authenticationManager; - } - - public MessageStore getMessageStore() - { - return _messageStore; - } -} - diff --git a/java/broker/src/test/java/org/apache/qpid/server/UnitTests.java b/java/broker/src/test/java/org/apache/qpid/server/UnitTests.java new file mode 100644 index 0000000000..fcae268288 --- /dev/null +++ b/java/broker/src/test/java/org/apache/qpid/server/UnitTests.java @@ -0,0 +1,39 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server; + +import junit.framework.JUnit4TestAdapter; +import org.junit.runner.RunWith; +import org.junit.runners.Suite; + +@RunWith(Suite.class) +@Suite.SuiteClasses({ + org.apache.qpid.server.configuration.UnitTests.class, + org.apache.qpid.server.exchange.UnitTests.class, + org.apache.qpid.server.util.UnitTests.class + }) +public class UnitTests +{ + public static junit.framework.Test suite() + { + return new JUnit4TestAdapter(UnitTests.class); + } +} diff --git a/java/broker/src/test/java/org/apache/qpid/server/configuration/TestPropertyUtils.java b/java/broker/src/test/java/org/apache/qpid/server/configuration/TestPropertyUtils.java new file mode 100644 index 0000000000..8bab0fbc12 --- /dev/null +++ b/java/broker/src/test/java/org/apache/qpid/server/configuration/TestPropertyUtils.java @@ -0,0 +1,53 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.configuration; + +import junit.framework.JUnit4TestAdapter; +import org.apache.qpid.configuration.PropertyException; +import org.apache.qpid.configuration.PropertyUtils; +import static org.junit.Assert.assertEquals; +import org.junit.Test; + +// TODO: This belongs in the "common" module. +public class TestPropertyUtils +{ + @Test + public void testSimpleExpansion() throws PropertyException + { + System.setProperty("banana", "fruity"); + String expandedProperty = PropertyUtils.replaceProperties("${banana}"); + assertEquals(expandedProperty, "fruity"); + } + + @Test + public void testDualExpansion() throws PropertyException + { + System.setProperty("banana", "fruity"); + System.setProperty("concrete", "horrible"); + String expandedProperty = PropertyUtils.replaceProperties("${banana}xyz${concrete}"); + assertEquals(expandedProperty, "fruityxyzhorrible"); + } + + public static junit.framework.Test suite() + { + return new JUnit4TestAdapter(TestPropertyUtils.class); + } +} diff --git a/java/broker/src/test/java/org/apache/qpid/server/configuration/UnitTests.java b/java/broker/src/test/java/org/apache/qpid/server/configuration/UnitTests.java new file mode 100644 index 0000000000..6e39e9efd1 --- /dev/null +++ b/java/broker/src/test/java/org/apache/qpid/server/configuration/UnitTests.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.server.configuration; + +import junit.framework.JUnit4TestAdapter; +import org.junit.runner.RunWith; +import org.junit.runners.Suite; + +@RunWith(Suite.class) +@Suite.SuiteClasses({TestPropertyUtils.class}) +public class UnitTests +{ + public static junit.framework.Test suite() + { + return new JUnit4TestAdapter(UnitTests.class); + } +} diff --git a/java/broker/src/test/java/org/apache/qpid/server/exchange/HeadersBindingTest.java b/java/broker/src/test/java/org/apache/qpid/server/exchange/HeadersBindingTest.java new file mode 100644 index 0000000000..0e7ab10c59 --- /dev/null +++ b/java/broker/src/test/java/org/apache/qpid/server/exchange/HeadersBindingTest.java @@ -0,0 +1,203 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.exchange; + +import org.junit.Test; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.assertFalse; + + +import java.util.Map; +import java.util.HashMap; + +import junit.framework.JUnit4TestAdapter; + +/** + */ +public class HeadersBindingTest +{ + private Map bindHeaders = new HashMap(); + private Map matchHeaders = new HashMap(); + + @Test public void default_1() + { + bindHeaders.put("A", "Value of A"); + + matchHeaders.put("A", "Value of A"); + + assertTrue(new HeadersBinding(bindHeaders).matches(matchHeaders)); + } + + @Test public void default_2() + { + bindHeaders.put("A", "Value of A"); + + matchHeaders.put("A", "Value of A"); + matchHeaders.put("B", "Value of B"); + + assertTrue(new HeadersBinding(bindHeaders).matches(matchHeaders)); + } + + @Test public void default_3() + { + bindHeaders.put("A", "Value of A"); + + matchHeaders.put("A", "Altered value of A"); + + assertFalse(new HeadersBinding(bindHeaders).matches(matchHeaders)); + } + + @Test public void all_1() + { + bindHeaders.put("X-match", "all"); + bindHeaders.put("A", "Value of A"); + + matchHeaders.put("A", "Value of A"); + + assertTrue(new HeadersBinding(bindHeaders).matches(matchHeaders)); + } + + @Test public void all_2() + { + bindHeaders.put("X-match", "all"); + bindHeaders.put("A", "Value of A"); + bindHeaders.put("B", "Value of B"); + + matchHeaders.put("A", "Value of A"); + + assertFalse(new HeadersBinding(bindHeaders).matches(matchHeaders)); + } + + @Test public void all_3() + { + bindHeaders.put("X-match", "all"); + bindHeaders.put("A", "Value of A"); + bindHeaders.put("B", "Value of B"); + + matchHeaders.put("A", "Value of A"); + matchHeaders.put("B", "Value of B"); + + assertTrue(new HeadersBinding(bindHeaders).matches(matchHeaders)); + } + + @Test public void all_4() + { + bindHeaders.put("X-match", "all"); + bindHeaders.put("A", "Value of A"); + bindHeaders.put("B", "Value of B"); + + matchHeaders.put("A", "Value of A"); + matchHeaders.put("B", "Value of B"); + matchHeaders.put("C", "Value of C"); + + assertTrue(new HeadersBinding(bindHeaders).matches(matchHeaders)); + } + + @Test public void all_5() + { + bindHeaders.put("X-match", "all"); + bindHeaders.put("A", "Value of A"); + bindHeaders.put("B", "Value of B"); + + matchHeaders.put("A", "Value of A"); + matchHeaders.put("B", "Altered value of B"); + matchHeaders.put("C", "Value of C"); + + assertFalse(new HeadersBinding(bindHeaders).matches(matchHeaders)); + } + + @Test public void any_1() + { + bindHeaders.put("X-match", "any"); + bindHeaders.put("A", "Value of A"); + + matchHeaders.put("A", "Value of A"); + + assertTrue(new HeadersBinding(bindHeaders).matches(matchHeaders)); + } + + @Test public void any_2() + { + bindHeaders.put("X-match", "any"); + bindHeaders.put("A", "Value of A"); + bindHeaders.put("B", "Value of B"); + + matchHeaders.put("A", "Value of A"); + + assertTrue(new HeadersBinding(bindHeaders).matches(matchHeaders)); + } + + @Test public void any_3() + { + bindHeaders.put("X-match", "any"); + bindHeaders.put("A", "Value of A"); + bindHeaders.put("B", "Value of B"); + + matchHeaders.put("A", "Value of A"); + matchHeaders.put("B", "Value of B"); + + assertTrue(new HeadersBinding(bindHeaders).matches(matchHeaders)); + } + + @Test public void any_4() + { + bindHeaders.put("X-match", "any"); + bindHeaders.put("A", "Value of A"); + bindHeaders.put("B", "Value of B"); + + matchHeaders.put("A", "Value of A"); + matchHeaders.put("B", "Value of B"); + matchHeaders.put("C", "Value of C"); + + assertTrue(new HeadersBinding(bindHeaders).matches(matchHeaders)); + } + + @Test public void any_5() + { + bindHeaders.put("X-match", "any"); + bindHeaders.put("A", "Value of A"); + bindHeaders.put("B", "Value of B"); + + matchHeaders.put("A", "Value of A"); + matchHeaders.put("B", "Altered value of B"); + matchHeaders.put("C", "Value of C"); + + assertTrue(new HeadersBinding(bindHeaders).matches(matchHeaders)); + } + + @Test public void any_6() + { + bindHeaders.put("X-match", "any"); + bindHeaders.put("A", "Value of A"); + bindHeaders.put("B", "Value of B"); + + matchHeaders.put("A", "Altered value of A"); + matchHeaders.put("B", "Altered value of B"); + matchHeaders.put("C", "Value of C"); + + assertFalse(new HeadersBinding(bindHeaders).matches(matchHeaders)); + } + public static junit.framework.Test suite() + { + return new JUnit4TestAdapter(HeadersBindingTest.class); + } + +} diff --git a/java/broker/src/test/java/org/apache/qpid/server/exchange/UnitTests.java b/java/broker/src/test/java/org/apache/qpid/server/exchange/UnitTests.java new file mode 100644 index 0000000000..ce3812be7f --- /dev/null +++ b/java/broker/src/test/java/org/apache/qpid/server/exchange/UnitTests.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.server.exchange; + +import junit.framework.JUnit4TestAdapter; +import org.junit.runner.RunWith; +import org.junit.runners.Suite; + +@RunWith(Suite.class) +@Suite.SuiteClasses({HeadersBindingTest.class}) +public class UnitTests +{ + public static junit.framework.Test suite() + { + return new JUnit4TestAdapter(UnitTests.class); + } +} diff --git a/java/broker/src/test/java/org/apache/qpid/server/util/LoggingProxyTest.java b/java/broker/src/test/java/org/apache/qpid/server/util/LoggingProxyTest.java new file mode 100644 index 0000000000..878500689a --- /dev/null +++ b/java/broker/src/test/java/org/apache/qpid/server/util/LoggingProxyTest.java @@ -0,0 +1,92 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.util; + +import junit.framework.JUnit4TestAdapter; +import org.junit.Assert; +import static org.junit.Assert.assertEquals; +import org.junit.Test; + +import java.util.Arrays; +import java.util.Collection; +import java.util.List; + +public class LoggingProxyTest +{ + static interface IFoo { + void foo(); + void foo(int i, Collection c); + String bar(); + String bar(String s, List l); + } + + static class Foo implements IFoo { + public void foo() + { + } + + public void foo(int i, Collection c) + { + } + + public String bar() + { + return null; + } + + public String bar(String s, List l) + { + return "ha"; + } + } + + @Test + public void simple() { + LoggingProxy proxy = new LoggingProxy(new Foo(), 20); + IFoo foo = (IFoo)proxy.getProxy(IFoo.class); + foo.foo(); + assertEquals(2, proxy.getBufferSize()); + Assert.assertTrue(proxy.getBuffer().get(0).toString().matches(".*: foo\\(\\) entered$")); + Assert.assertTrue(proxy.getBuffer().get(1).toString().matches(".*: foo\\(\\) returned$")); + + foo.foo(3, Arrays.asList(0, 1, 2)); + assertEquals(4, proxy.getBufferSize()); + Assert.assertTrue(proxy.getBuffer().get(2).toString().matches(".*: foo\\(\\[3, \\[0, 1, 2\\]\\]\\) entered$")); + Assert.assertTrue(proxy.getBuffer().get(3).toString().matches(".*: foo\\(\\) returned$")); + + foo.bar(); + assertEquals(6, proxy.getBufferSize()); + Assert.assertTrue(proxy.getBuffer().get(4).toString().matches(".*: bar\\(\\) entered$")); + Assert.assertTrue(proxy.getBuffer().get(5).toString().matches(".*: bar\\(\\) returned null$")); + + foo.bar("hello", Arrays.asList(1, 2, 3)); + assertEquals(8, proxy.getBufferSize()); + Assert.assertTrue(proxy.getBuffer().get(6).toString().matches(".*: bar\\(\\[hello, \\[1, 2, 3\\]\\]\\) entered$")); + Assert.assertTrue(proxy.getBuffer().get(7).toString().matches(".*: bar\\(\\) returned ha$")); + + proxy.dump(); + } + + public static junit.framework.Test suite() + { + return new JUnit4TestAdapter(LoggingProxyTest.class); + } +} diff --git a/java/broker/src/test/java/org/apache/qpid/server/util/UnitTests.java b/java/broker/src/test/java/org/apache/qpid/server/util/UnitTests.java new file mode 100644 index 0000000000..5314fa0df8 --- /dev/null +++ b/java/broker/src/test/java/org/apache/qpid/server/util/UnitTests.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.server.util; + +import junit.framework.JUnit4TestAdapter; +import org.junit.runner.RunWith; +import org.junit.runners.Suite; + +@RunWith(Suite.class) +@Suite.SuiteClasses({LoggingProxyTest.class}) +public class UnitTests +{ + public static junit.framework.Test suite() + { + return new JUnit4TestAdapter(UnitTests.class); + } +} -- cgit v1.2.1