From 5c2e6ee403cc132ecb2b04b5f266a57a1980bca9 Mon Sep 17 00:00:00 2001 From: Robert Greig Date: Thu, 23 Nov 2006 22:21:46 +0000 Subject: Start of merge from trunk - some manual restructuring git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/branches/new_persistence@478686 13f79535-47bb-0310-9956-ffa450edef68 --- java/broker/main/log4j.properties | 6 + .../main/org/apache/qpid/server/AMQChannel.java | 565 +++++++++++++++ .../qpid/server/ConsumerTagNotUniqueException.java | 22 + java/broker/main/org/apache/qpid/server/Main.java | 613 +++++++++++++++++ .../org/apache/qpid/server/ManagedChannel.java | 64 ++ .../qpid/server/RequiredDeliveryException.java | 49 ++ .../main/org/apache/qpid/server/ack/TxAck.java | 125 ++++ .../qpid/server/ack/UnacknowledgedMessage.java | 48 ++ .../qpid/server/ack/UnacknowledgedMessageMap.java | 62 ++ .../server/ack/UnacknowledgedMessageMapImpl.java | 211 ++++++ .../qpid/server/configuration/Configurator.java | 102 +++ .../configuration/VirtualHostConfiguration.java | 217 ++++++ .../qpid/server/exchange/AbstractExchange.java | 136 ++++ .../server/exchange/DefaultExchangeFactory.java | 63 ++ .../server/exchange/DefaultExchangeRegistry.java | 93 +++ .../qpid/server/exchange/DestNameExchange.java | 219 ++++++ .../qpid/server/exchange/DestWildExchange.java | 223 ++++++ .../org/apache/qpid/server/exchange/Exchange.java | 47 ++ .../qpid/server/exchange/ExchangeFactory.java | 28 + .../server/exchange/ExchangeInUseException.java | 28 + .../qpid/server/exchange/ExchangeRegistry.java | 38 + .../qpid/server/exchange/HeadersBinding.java | 142 ++++ .../qpid/server/exchange/HeadersExchange.java | 239 +++++++ .../org/apache/qpid/server/exchange/Index.java | 85 +++ .../qpid/server/exchange/ManagedExchange.java | 90 +++ .../apache/qpid/server/exchange/MessageRouter.java | 37 + .../qpid/server/exchange/NoRouteException.java | 39 ++ .../qpid/server/handler/BasicAckMethodHandler.java | 52 ++ .../server/handler/BasicCancelMethodHandler.java | 58 ++ .../server/handler/BasicConsumeMethodHandler.java | 90 +++ .../server/handler/BasicPublishMethodHandler.java | 77 +++ .../qpid/server/handler/BasicQosHandler.java | 46 ++ .../server/handler/BasicRecoverMethodHandler.java | 54 ++ .../qpid/server/handler/ChannelCloseHandler.java | 58 ++ .../qpid/server/handler/ChannelCloseOkHandler.java | 51 ++ .../qpid/server/handler/ChannelFlowHandler.java | 61 ++ .../qpid/server/handler/ChannelOpenHandler.java | 58 ++ .../handler/ConnectionCloseMethodHandler.java | 65 ++ .../handler/ConnectionCloseOkMethodHandler.java | 63 ++ .../handler/ConnectionOpenMethodHandler.java | 68 ++ .../handler/ConnectionSecureOkMethodHandler.java | 115 ++++ .../handler/ConnectionStartOkMethodHandler.java | 127 ++++ .../handler/ConnectionTuneOkMethodHandler.java | 54 ++ .../server/handler/ExchangeDeclareHandler.java | 79 +++ .../qpid/server/handler/ExchangeDeleteHandler.java | 62 ++ .../server/handler/OnCurrentThreadExecutor.java | 31 + .../qpid/server/handler/QueueBindHandler.java | 94 +++ .../qpid/server/handler/QueueDeclareHandler.java | 124 ++++ .../qpid/server/handler/QueueDeleteHandler.java | 84 +++ .../qpid/server/handler/TxCommitHandler.java | 61 ++ .../qpid/server/handler/TxRollbackHandler.java | 59 ++ .../qpid/server/handler/TxSelectHandler.java | 50 ++ .../org/apache/qpid/server/jms/JmsConsumer.java | 107 +++ .../qpid/server/management/AMQManagedObject.java | 94 +++ .../server/management/DefaultManagedObject.java | 168 +++++ .../management/JMXManagedObjectRegistry.java | 49 ++ .../qpid/server/management/MBeanAttribute.java | 39 ++ .../qpid/server/management/MBeanConstructor.java | 37 + .../qpid/server/management/MBeanDescription.java | 36 + .../qpid/server/management/MBeanIntrospector.java | 385 +++++++++++ .../qpid/server/management/MBeanOperation.java | 40 ++ .../server/management/MBeanOperationParameter.java | 35 + .../apache/qpid/server/management/Managable.java | 31 + .../qpid/server/management/ManagedBroker.java | 95 +++ .../qpid/server/management/ManagedObject.java | 55 ++ .../server/management/ManagedObjectRegistry.java | 39 ++ .../server/management/ManagementConfiguration.java | 27 + .../management/NoopManagedObjectRegistry.java | 45 ++ .../qpid/server/protocol/AMQMethodEvent.java | 62 ++ .../qpid/server/protocol/AMQMethodListener.java | 52 ++ .../server/protocol/AMQMinaProtocolSession.java | 681 ++++++++++++++++++ .../server/protocol/AMQPFastProtocolHandler.java | 227 ++++++ .../qpid/server/protocol/AMQPProtocolProvider.java | 50 ++ .../qpid/server/protocol/AMQProtocolSession.java | 122 ++++ .../qpid/server/protocol/ExchangeInitialiser.java | 38 + .../qpid/server/protocol/HeartbeatConfig.java | 64 ++ .../qpid/server/protocol/ManagedConnection.java | 138 ++++ .../qpid/server/protocol/ManagedSession.java | 33 + .../org/apache/qpid/server/queue/AMQMessage.java | 520 ++++++++++++++ .../apache/qpid/server/queue/AMQMessageHandle.java | 62 ++ .../org/apache/qpid/server/queue/AMQQueue.java | 764 +++++++++++++++++++++ .../qpid/server/queue/AsyncDeliveryConfig.java | 53 ++ .../qpid/server/queue/DefaultQueueRegistry.java | 47 ++ .../apache/qpid/server/queue/DeliveryManager.java | 259 +++++++ .../apache/qpid/server/queue/ExchangeBindings.java | 109 +++ .../qpid/server/queue/FailedDequeueException.java | 36 + .../qpid/server/queue/InMemoryMessageHandle.java | 110 +++ .../org/apache/qpid/server/queue/ManagedQueue.java | 213 ++++++ .../qpid/server/queue/MessageCleanupException.java | 32 + .../qpid/server/queue/MessageHandleFactory.java | 34 + .../apache/qpid/server/queue/MessageMetaData.java | 70 ++ .../qpid/server/queue/NoConsumersException.java | 39 ++ .../apache/qpid/server/queue/QueueRegistry.java | 30 + .../org/apache/qpid/server/queue/Subscription.java | 29 + .../qpid/server/queue/SubscriptionFactory.java | 37 + .../apache/qpid/server/queue/SubscriptionImpl.java | 170 +++++ .../qpid/server/queue/SubscriptionManager.java | 28 + .../apache/qpid/server/queue/SubscriptionSet.java | 182 +++++ .../server/queue/WeakReferenceMessageHandle.java | 144 ++++ .../server/queue/WeightedSubscriptionManager.java | 23 + .../qpid/server/registry/ApplicationRegistry.java | 197 ++++++ .../ConfigurationFileApplicationRegistry.java | 155 +++++ .../qpid/server/registry/IApplicationRegistry.java | 65 ++ .../security/auth/AuthenticationManager.java | 30 + .../auth/AuthenticationProviderInitialiser.java | 63 ++ .../server/security/auth/AuthenticationResult.java | 40 ++ .../server/security/auth/CRAMMD5Initialiser.java | 35 + .../qpid/server/security/auth/JCAProvider.java | 43 ++ .../security/auth/NullAuthenticationManager.java | 82 +++ .../auth/PasswordFilePrincipalDatabase.java | 130 ++++ .../server/security/auth/PrincipalDatabase.java | 42 ++ .../security/auth/SASLAuthenticationManager.java | 224 ++++++ .../security/auth/UsernamePasswordInitialiser.java | 99 +++ .../server/security/auth/UsernamePrincipal.java | 39 ++ .../auth/amqplain/AmqPlainInitialiser.java | 35 + .../security/auth/amqplain/AmqPlainSaslServer.java | 120 ++++ .../auth/amqplain/AmqPlainSaslServerFactory.java | 56 ++ .../security/auth/plain/PlainInitialiser.java | 35 + .../security/auth/plain/PlainSaslServer.java | 141 ++++ .../auth/plain/PlainSaslServerFactory.java | 56 ++ .../org/apache/qpid/server/state/AMQState.java | 33 + .../apache/qpid/server/state/AMQStateManager.java | 219 ++++++ .../state/IllegalStateTransitionException.java | 45 ++ .../server/state/StateAwareMethodListener.java | 37 + .../apache/qpid/server/state/StateListener.java | 27 + .../qpid/server/store/MemoryMessageStore.java | 172 +++++ .../org/apache/qpid/server/store/MessageStore.java | 87 +++ .../server/transport/ConnectorConfiguration.java | 83 +++ .../qpid/server/transport/ThreadPoolFilter.java | 692 +++++++++++++++++++ .../qpid/server/txn/CleanupMessageOperation.java | 89 +++ .../qpid/server/txn/DeliverMessageOperation.java | 61 ++ .../qpid/server/txn/LocalTransactionalContext.java | 149 ++++ .../qpid/server/txn/NonTransactionalContext.java | 171 +++++ .../qpid/server/txn/StoreMessageOperation.java | 45 ++ .../qpid/server/txn/TransactionalContext.java | 33 + .../main/org/apache/qpid/server/txn/TxnBuffer.java | 119 ++++ .../main/org/apache/qpid/server/txn/TxnOp.java | 51 ++ .../apache/qpid/server/util/CircularBuffer.java | 123 ++++ .../org/apache/qpid/server/util/LoggingProxy.java | 102 +++ .../qpid/server/util/NullApplicationRegistry.java | 106 +++ java/broker/src/log4j.properties | 6 - .../src/org/apache/qpid/server/AMQChannel.java | 565 --------------- .../qpid/server/ConsumerTagNotUniqueException.java | 22 - java/broker/src/org/apache/qpid/server/Main.java | 613 ----------------- .../src/org/apache/qpid/server/ManagedChannel.java | 64 -- .../qpid/server/RequiredDeliveryException.java | 49 -- .../src/org/apache/qpid/server/ack/TxAck.java | 125 ---- .../qpid/server/ack/UnacknowledgedMessage.java | 48 -- .../qpid/server/ack/UnacknowledgedMessageMap.java | 62 -- .../server/ack/UnacknowledgedMessageMapImpl.java | 211 ------ .../qpid/server/configuration/Configurator.java | 102 --- .../configuration/VirtualHostConfiguration.java | 217 ------ .../qpid/server/exchange/AbstractExchange.java | 136 ---- .../server/exchange/DefaultExchangeFactory.java | 63 -- .../server/exchange/DefaultExchangeRegistry.java | 93 --- .../qpid/server/exchange/DestNameExchange.java | 219 ------ .../qpid/server/exchange/DestWildExchange.java | 223 ------ .../org/apache/qpid/server/exchange/Exchange.java | 47 -- .../qpid/server/exchange/ExchangeFactory.java | 28 - .../server/exchange/ExchangeInUseException.java | 28 - .../qpid/server/exchange/ExchangeRegistry.java | 38 - .../qpid/server/exchange/HeadersBinding.java | 142 ---- .../qpid/server/exchange/HeadersExchange.java | 239 ------- .../src/org/apache/qpid/server/exchange/Index.java | 85 --- .../qpid/server/exchange/ManagedExchange.java | 90 --- .../apache/qpid/server/exchange/MessageRouter.java | 37 - .../qpid/server/exchange/NoRouteException.java | 39 -- .../qpid/server/handler/BasicAckMethodHandler.java | 52 -- .../server/handler/BasicCancelMethodHandler.java | 58 -- .../server/handler/BasicConsumeMethodHandler.java | 90 --- .../server/handler/BasicPublishMethodHandler.java | 77 --- .../qpid/server/handler/BasicQosHandler.java | 46 -- .../server/handler/BasicRecoverMethodHandler.java | 54 -- .../qpid/server/handler/ChannelCloseHandler.java | 58 -- .../qpid/server/handler/ChannelCloseOkHandler.java | 51 -- .../qpid/server/handler/ChannelFlowHandler.java | 61 -- .../qpid/server/handler/ChannelOpenHandler.java | 58 -- .../handler/ConnectionCloseMethodHandler.java | 65 -- .../handler/ConnectionCloseOkMethodHandler.java | 63 -- .../handler/ConnectionOpenMethodHandler.java | 68 -- .../handler/ConnectionSecureOkMethodHandler.java | 115 ---- .../handler/ConnectionStartOkMethodHandler.java | 127 ---- .../handler/ConnectionTuneOkMethodHandler.java | 54 -- .../server/handler/ExchangeDeclareHandler.java | 79 --- .../qpid/server/handler/ExchangeDeleteHandler.java | 62 -- .../server/handler/OnCurrentThreadExecutor.java | 31 - .../qpid/server/handler/QueueBindHandler.java | 94 --- .../qpid/server/handler/QueueDeclareHandler.java | 124 ---- .../qpid/server/handler/QueueDeleteHandler.java | 84 --- .../qpid/server/handler/TxCommitHandler.java | 61 -- .../qpid/server/handler/TxRollbackHandler.java | 59 -- .../qpid/server/handler/TxSelectHandler.java | 50 -- .../org/apache/qpid/server/jms/JmsConsumer.java | 107 --- .../qpid/server/management/AMQManagedObject.java | 94 --- .../server/management/DefaultManagedObject.java | 168 ----- .../management/JMXManagedObjectRegistry.java | 49 -- .../qpid/server/management/MBeanAttribute.java | 39 -- .../qpid/server/management/MBeanConstructor.java | 37 - .../qpid/server/management/MBeanDescription.java | 36 - .../qpid/server/management/MBeanIntrospector.java | 385 ----------- .../qpid/server/management/MBeanOperation.java | 40 -- .../server/management/MBeanOperationParameter.java | 35 - .../apache/qpid/server/management/Managable.java | 31 - .../qpid/server/management/ManagedBroker.java | 95 --- .../qpid/server/management/ManagedObject.java | 55 -- .../server/management/ManagedObjectRegistry.java | 39 -- .../server/management/ManagementConfiguration.java | 27 - .../management/NoopManagedObjectRegistry.java | 45 -- .../qpid/server/protocol/AMQMethodEvent.java | 62 -- .../qpid/server/protocol/AMQMethodListener.java | 52 -- .../server/protocol/AMQMinaProtocolSession.java | 681 ------------------ .../server/protocol/AMQPFastProtocolHandler.java | 227 ------ .../qpid/server/protocol/AMQPProtocolProvider.java | 50 -- .../qpid/server/protocol/AMQProtocolSession.java | 122 ---- .../qpid/server/protocol/ExchangeInitialiser.java | 38 - .../qpid/server/protocol/HeartbeatConfig.java | 64 -- .../qpid/server/protocol/ManagedConnection.java | 138 ---- .../qpid/server/protocol/ManagedSession.java | 33 - .../org/apache/qpid/server/queue/AMQMessage.java | 520 -------------- .../apache/qpid/server/queue/AMQMessageHandle.java | 62 -- .../src/org/apache/qpid/server/queue/AMQQueue.java | 764 --------------------- .../qpid/server/queue/AsyncDeliveryConfig.java | 53 -- .../qpid/server/queue/DefaultQueueRegistry.java | 47 -- .../apache/qpid/server/queue/DeliveryManager.java | 259 ------- .../apache/qpid/server/queue/ExchangeBindings.java | 109 --- .../qpid/server/queue/FailedDequeueException.java | 36 - .../qpid/server/queue/InMemoryMessageHandle.java | 110 --- .../org/apache/qpid/server/queue/ManagedQueue.java | 213 ------ .../qpid/server/queue/MessageCleanupException.java | 32 - .../qpid/server/queue/MessageHandleFactory.java | 34 - .../apache/qpid/server/queue/MessageMetaData.java | 70 -- .../qpid/server/queue/NoConsumersException.java | 39 -- .../apache/qpid/server/queue/QueueRegistry.java | 30 - .../org/apache/qpid/server/queue/Subscription.java | 29 - .../qpid/server/queue/SubscriptionFactory.java | 37 - .../apache/qpid/server/queue/SubscriptionImpl.java | 170 ----- .../qpid/server/queue/SubscriptionManager.java | 28 - .../apache/qpid/server/queue/SubscriptionSet.java | 182 ----- .../server/queue/WeakReferenceMessageHandle.java | 144 ---- .../server/queue/WeightedSubscriptionManager.java | 23 - .../qpid/server/registry/ApplicationRegistry.java | 197 ------ .../ConfigurationFileApplicationRegistry.java | 155 ----- .../qpid/server/registry/IApplicationRegistry.java | 65 -- .../security/auth/AuthenticationManager.java | 30 - .../auth/AuthenticationProviderInitialiser.java | 63 -- .../server/security/auth/AuthenticationResult.java | 40 -- .../server/security/auth/CRAMMD5Initialiser.java | 35 - .../qpid/server/security/auth/JCAProvider.java | 43 -- .../security/auth/NullAuthenticationManager.java | 82 --- .../auth/PasswordFilePrincipalDatabase.java | 130 ---- .../server/security/auth/PrincipalDatabase.java | 42 -- .../security/auth/SASLAuthenticationManager.java | 224 ------ .../security/auth/UsernamePasswordInitialiser.java | 99 --- .../server/security/auth/UsernamePrincipal.java | 39 -- .../auth/amqplain/AmqPlainInitialiser.java | 35 - .../security/auth/amqplain/AmqPlainSaslServer.java | 120 ---- .../auth/amqplain/AmqPlainSaslServerFactory.java | 56 -- .../security/auth/plain/PlainInitialiser.java | 35 - .../security/auth/plain/PlainSaslServer.java | 141 ---- .../auth/plain/PlainSaslServerFactory.java | 56 -- .../src/org/apache/qpid/server/state/AMQState.java | 33 - .../apache/qpid/server/state/AMQStateManager.java | 219 ------ .../state/IllegalStateTransitionException.java | 45 -- .../server/state/StateAwareMethodListener.java | 37 - .../apache/qpid/server/state/StateListener.java | 27 - .../qpid/server/store/MemoryMessageStore.java | 172 ----- .../org/apache/qpid/server/store/MessageStore.java | 87 --- .../server/transport/ConnectorConfiguration.java | 83 --- .../qpid/server/transport/ThreadPoolFilter.java | 692 ------------------- .../qpid/server/txn/CleanupMessageOperation.java | 89 --- .../qpid/server/txn/DeliverMessageOperation.java | 61 -- .../qpid/server/txn/LocalTransactionalContext.java | 149 ---- .../qpid/server/txn/NonTransactionalContext.java | 171 ----- .../qpid/server/txn/StoreMessageOperation.java | 45 -- .../qpid/server/txn/TransactionalContext.java | 33 - .../src/org/apache/qpid/server/txn/TxnBuffer.java | 119 ---- .../src/org/apache/qpid/server/txn/TxnOp.java | 51 -- .../apache/qpid/server/util/CircularBuffer.java | 123 ---- .../org/apache/qpid/server/util/LoggingProxy.java | 102 --- .../qpid/server/util/NullApplicationRegistry.java | 106 --- 280 files changed, 15203 insertions(+), 15203 deletions(-) create mode 100644 java/broker/main/log4j.properties create mode 100644 java/broker/main/org/apache/qpid/server/AMQChannel.java create mode 100644 java/broker/main/org/apache/qpid/server/ConsumerTagNotUniqueException.java create mode 100644 java/broker/main/org/apache/qpid/server/Main.java create mode 100644 java/broker/main/org/apache/qpid/server/ManagedChannel.java create mode 100644 java/broker/main/org/apache/qpid/server/RequiredDeliveryException.java create mode 100644 java/broker/main/org/apache/qpid/server/ack/TxAck.java create mode 100644 java/broker/main/org/apache/qpid/server/ack/UnacknowledgedMessage.java create mode 100644 java/broker/main/org/apache/qpid/server/ack/UnacknowledgedMessageMap.java create mode 100644 java/broker/main/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java create mode 100644 java/broker/main/org/apache/qpid/server/configuration/Configurator.java create mode 100644 java/broker/main/org/apache/qpid/server/configuration/VirtualHostConfiguration.java create mode 100644 java/broker/main/org/apache/qpid/server/exchange/AbstractExchange.java create mode 100644 java/broker/main/org/apache/qpid/server/exchange/DefaultExchangeFactory.java create mode 100644 java/broker/main/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java create mode 100644 java/broker/main/org/apache/qpid/server/exchange/DestNameExchange.java create mode 100644 java/broker/main/org/apache/qpid/server/exchange/DestWildExchange.java create mode 100644 java/broker/main/org/apache/qpid/server/exchange/Exchange.java create mode 100644 java/broker/main/org/apache/qpid/server/exchange/ExchangeFactory.java create mode 100644 java/broker/main/org/apache/qpid/server/exchange/ExchangeInUseException.java create mode 100644 java/broker/main/org/apache/qpid/server/exchange/ExchangeRegistry.java create mode 100644 java/broker/main/org/apache/qpid/server/exchange/HeadersBinding.java create mode 100644 java/broker/main/org/apache/qpid/server/exchange/HeadersExchange.java create mode 100644 java/broker/main/org/apache/qpid/server/exchange/Index.java create mode 100644 java/broker/main/org/apache/qpid/server/exchange/ManagedExchange.java create mode 100644 java/broker/main/org/apache/qpid/server/exchange/MessageRouter.java create mode 100644 java/broker/main/org/apache/qpid/server/exchange/NoRouteException.java create mode 100644 java/broker/main/org/apache/qpid/server/handler/BasicAckMethodHandler.java create mode 100644 java/broker/main/org/apache/qpid/server/handler/BasicCancelMethodHandler.java create mode 100644 java/broker/main/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java create mode 100644 java/broker/main/org/apache/qpid/server/handler/BasicPublishMethodHandler.java create mode 100644 java/broker/main/org/apache/qpid/server/handler/BasicQosHandler.java create mode 100644 java/broker/main/org/apache/qpid/server/handler/BasicRecoverMethodHandler.java create mode 100644 java/broker/main/org/apache/qpid/server/handler/ChannelCloseHandler.java create mode 100644 java/broker/main/org/apache/qpid/server/handler/ChannelCloseOkHandler.java create mode 100644 java/broker/main/org/apache/qpid/server/handler/ChannelFlowHandler.java create mode 100644 java/broker/main/org/apache/qpid/server/handler/ChannelOpenHandler.java create mode 100644 java/broker/main/org/apache/qpid/server/handler/ConnectionCloseMethodHandler.java create mode 100644 java/broker/main/org/apache/qpid/server/handler/ConnectionCloseOkMethodHandler.java create mode 100644 java/broker/main/org/apache/qpid/server/handler/ConnectionOpenMethodHandler.java create mode 100644 java/broker/main/org/apache/qpid/server/handler/ConnectionSecureOkMethodHandler.java create mode 100644 java/broker/main/org/apache/qpid/server/handler/ConnectionStartOkMethodHandler.java create mode 100644 java/broker/main/org/apache/qpid/server/handler/ConnectionTuneOkMethodHandler.java create mode 100644 java/broker/main/org/apache/qpid/server/handler/ExchangeDeclareHandler.java create mode 100644 java/broker/main/org/apache/qpid/server/handler/ExchangeDeleteHandler.java create mode 100644 java/broker/main/org/apache/qpid/server/handler/OnCurrentThreadExecutor.java create mode 100644 java/broker/main/org/apache/qpid/server/handler/QueueBindHandler.java create mode 100644 java/broker/main/org/apache/qpid/server/handler/QueueDeclareHandler.java create mode 100644 java/broker/main/org/apache/qpid/server/handler/QueueDeleteHandler.java create mode 100644 java/broker/main/org/apache/qpid/server/handler/TxCommitHandler.java create mode 100644 java/broker/main/org/apache/qpid/server/handler/TxRollbackHandler.java create mode 100644 java/broker/main/org/apache/qpid/server/handler/TxSelectHandler.java create mode 100644 java/broker/main/org/apache/qpid/server/jms/JmsConsumer.java create mode 100644 java/broker/main/org/apache/qpid/server/management/AMQManagedObject.java create mode 100644 java/broker/main/org/apache/qpid/server/management/DefaultManagedObject.java create mode 100644 java/broker/main/org/apache/qpid/server/management/JMXManagedObjectRegistry.java create mode 100644 java/broker/main/org/apache/qpid/server/management/MBeanAttribute.java create mode 100644 java/broker/main/org/apache/qpid/server/management/MBeanConstructor.java create mode 100644 java/broker/main/org/apache/qpid/server/management/MBeanDescription.java create mode 100644 java/broker/main/org/apache/qpid/server/management/MBeanIntrospector.java create mode 100644 java/broker/main/org/apache/qpid/server/management/MBeanOperation.java create mode 100644 java/broker/main/org/apache/qpid/server/management/MBeanOperationParameter.java create mode 100644 java/broker/main/org/apache/qpid/server/management/Managable.java create mode 100644 java/broker/main/org/apache/qpid/server/management/ManagedBroker.java create mode 100644 java/broker/main/org/apache/qpid/server/management/ManagedObject.java create mode 100644 java/broker/main/org/apache/qpid/server/management/ManagedObjectRegistry.java create mode 100644 java/broker/main/org/apache/qpid/server/management/ManagementConfiguration.java create mode 100644 java/broker/main/org/apache/qpid/server/management/NoopManagedObjectRegistry.java create mode 100644 java/broker/main/org/apache/qpid/server/protocol/AMQMethodEvent.java create mode 100644 java/broker/main/org/apache/qpid/server/protocol/AMQMethodListener.java create mode 100644 java/broker/main/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java create mode 100644 java/broker/main/org/apache/qpid/server/protocol/AMQPFastProtocolHandler.java create mode 100644 java/broker/main/org/apache/qpid/server/protocol/AMQPProtocolProvider.java create mode 100644 java/broker/main/org/apache/qpid/server/protocol/AMQProtocolSession.java create mode 100644 java/broker/main/org/apache/qpid/server/protocol/ExchangeInitialiser.java create mode 100644 java/broker/main/org/apache/qpid/server/protocol/HeartbeatConfig.java create mode 100644 java/broker/main/org/apache/qpid/server/protocol/ManagedConnection.java create mode 100644 java/broker/main/org/apache/qpid/server/protocol/ManagedSession.java create mode 100644 java/broker/main/org/apache/qpid/server/queue/AMQMessage.java create mode 100644 java/broker/main/org/apache/qpid/server/queue/AMQMessageHandle.java create mode 100644 java/broker/main/org/apache/qpid/server/queue/AMQQueue.java create mode 100644 java/broker/main/org/apache/qpid/server/queue/AsyncDeliveryConfig.java create mode 100644 java/broker/main/org/apache/qpid/server/queue/DefaultQueueRegistry.java create mode 100644 java/broker/main/org/apache/qpid/server/queue/DeliveryManager.java create mode 100644 java/broker/main/org/apache/qpid/server/queue/ExchangeBindings.java create mode 100644 java/broker/main/org/apache/qpid/server/queue/FailedDequeueException.java create mode 100644 java/broker/main/org/apache/qpid/server/queue/InMemoryMessageHandle.java create mode 100644 java/broker/main/org/apache/qpid/server/queue/ManagedQueue.java create mode 100644 java/broker/main/org/apache/qpid/server/queue/MessageCleanupException.java create mode 100644 java/broker/main/org/apache/qpid/server/queue/MessageHandleFactory.java create mode 100644 java/broker/main/org/apache/qpid/server/queue/MessageMetaData.java create mode 100644 java/broker/main/org/apache/qpid/server/queue/NoConsumersException.java create mode 100644 java/broker/main/org/apache/qpid/server/queue/QueueRegistry.java create mode 100644 java/broker/main/org/apache/qpid/server/queue/Subscription.java create mode 100644 java/broker/main/org/apache/qpid/server/queue/SubscriptionFactory.java create mode 100644 java/broker/main/org/apache/qpid/server/queue/SubscriptionImpl.java create mode 100644 java/broker/main/org/apache/qpid/server/queue/SubscriptionManager.java create mode 100644 java/broker/main/org/apache/qpid/server/queue/SubscriptionSet.java create mode 100644 java/broker/main/org/apache/qpid/server/queue/WeakReferenceMessageHandle.java create mode 100644 java/broker/main/org/apache/qpid/server/queue/WeightedSubscriptionManager.java create mode 100644 java/broker/main/org/apache/qpid/server/registry/ApplicationRegistry.java create mode 100644 java/broker/main/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java create mode 100644 java/broker/main/org/apache/qpid/server/registry/IApplicationRegistry.java create mode 100644 java/broker/main/org/apache/qpid/server/security/auth/AuthenticationManager.java create mode 100644 java/broker/main/org/apache/qpid/server/security/auth/AuthenticationProviderInitialiser.java create mode 100644 java/broker/main/org/apache/qpid/server/security/auth/AuthenticationResult.java create mode 100644 java/broker/main/org/apache/qpid/server/security/auth/CRAMMD5Initialiser.java create mode 100644 java/broker/main/org/apache/qpid/server/security/auth/JCAProvider.java create mode 100644 java/broker/main/org/apache/qpid/server/security/auth/NullAuthenticationManager.java create mode 100644 java/broker/main/org/apache/qpid/server/security/auth/PasswordFilePrincipalDatabase.java create mode 100644 java/broker/main/org/apache/qpid/server/security/auth/PrincipalDatabase.java create mode 100644 java/broker/main/org/apache/qpid/server/security/auth/SASLAuthenticationManager.java create mode 100644 java/broker/main/org/apache/qpid/server/security/auth/UsernamePasswordInitialiser.java create mode 100644 java/broker/main/org/apache/qpid/server/security/auth/UsernamePrincipal.java create mode 100644 java/broker/main/org/apache/qpid/server/security/auth/amqplain/AmqPlainInitialiser.java create mode 100644 java/broker/main/org/apache/qpid/server/security/auth/amqplain/AmqPlainSaslServer.java create mode 100644 java/broker/main/org/apache/qpid/server/security/auth/amqplain/AmqPlainSaslServerFactory.java create mode 100644 java/broker/main/org/apache/qpid/server/security/auth/plain/PlainInitialiser.java create mode 100644 java/broker/main/org/apache/qpid/server/security/auth/plain/PlainSaslServer.java create mode 100644 java/broker/main/org/apache/qpid/server/security/auth/plain/PlainSaslServerFactory.java create mode 100644 java/broker/main/org/apache/qpid/server/state/AMQState.java create mode 100644 java/broker/main/org/apache/qpid/server/state/AMQStateManager.java create mode 100644 java/broker/main/org/apache/qpid/server/state/IllegalStateTransitionException.java create mode 100644 java/broker/main/org/apache/qpid/server/state/StateAwareMethodListener.java create mode 100644 java/broker/main/org/apache/qpid/server/state/StateListener.java create mode 100644 java/broker/main/org/apache/qpid/server/store/MemoryMessageStore.java create mode 100644 java/broker/main/org/apache/qpid/server/store/MessageStore.java create mode 100644 java/broker/main/org/apache/qpid/server/transport/ConnectorConfiguration.java create mode 100644 java/broker/main/org/apache/qpid/server/transport/ThreadPoolFilter.java create mode 100644 java/broker/main/org/apache/qpid/server/txn/CleanupMessageOperation.java create mode 100644 java/broker/main/org/apache/qpid/server/txn/DeliverMessageOperation.java create mode 100644 java/broker/main/org/apache/qpid/server/txn/LocalTransactionalContext.java create mode 100644 java/broker/main/org/apache/qpid/server/txn/NonTransactionalContext.java create mode 100644 java/broker/main/org/apache/qpid/server/txn/StoreMessageOperation.java create mode 100644 java/broker/main/org/apache/qpid/server/txn/TransactionalContext.java create mode 100644 java/broker/main/org/apache/qpid/server/txn/TxnBuffer.java create mode 100644 java/broker/main/org/apache/qpid/server/txn/TxnOp.java create mode 100644 java/broker/main/org/apache/qpid/server/util/CircularBuffer.java create mode 100644 java/broker/main/org/apache/qpid/server/util/LoggingProxy.java create mode 100644 java/broker/main/org/apache/qpid/server/util/NullApplicationRegistry.java delete mode 100644 java/broker/src/log4j.properties 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/protocol/ManagedSession.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/AMQMessageHandle.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/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/InMemoryMessageHandle.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/MessageHandleFactory.java delete mode 100644 java/broker/src/org/apache/qpid/server/queue/MessageMetaData.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/WeakReferenceMessageHandle.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/CleanupMessageOperation.java delete mode 100644 java/broker/src/org/apache/qpid/server/txn/DeliverMessageOperation.java delete mode 100644 java/broker/src/org/apache/qpid/server/txn/LocalTransactionalContext.java delete mode 100644 java/broker/src/org/apache/qpid/server/txn/NonTransactionalContext.java delete mode 100644 java/broker/src/org/apache/qpid/server/txn/StoreMessageOperation.java delete mode 100644 java/broker/src/org/apache/qpid/server/txn/TransactionalContext.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/LoggingProxy.java delete mode 100644 java/broker/src/org/apache/qpid/server/util/NullApplicationRegistry.java (limited to 'java') diff --git a/java/broker/main/log4j.properties b/java/broker/main/log4j.properties new file mode 100644 index 0000000000..3ff6f0b581 --- /dev/null +++ b/java/broker/main/log4j.properties @@ -0,0 +1,6 @@ +log4j.rootCategory=${amqj.logging.level}, console + +log4j.appender.console=org.apache.log4j.ConsoleAppender +log4j.appender.console.Threshold=info +log4j.appender.console.layout=org.apache.log4j.PatternLayout +log4j.appender.console.layout.ConversionPattern=%t %d %p [%c{4}] %m%n diff --git a/java/broker/main/org/apache/qpid/server/AMQChannel.java b/java/broker/main/org/apache/qpid/server/AMQChannel.java new file mode 100644 index 0000000000..e3d9bc31ff --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/AMQChannel.java @@ -0,0 +1,565 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.qpid.server; + +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.BasicPublishBody; +import org.apache.qpid.framing.ContentBody; +import org.apache.qpid.framing.ContentHeaderBody; +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.MessageHandleFactory; +import org.apache.qpid.server.store.MessageStore; +import org.apache.qpid.server.txn.LocalTransactionalContext; +import org.apache.qpid.server.txn.TransactionalContext; +import org.apache.qpid.server.txn.TxnBuffer; +import org.apache.qpid.server.txn.NonTransactionalContext; + +import javax.management.MalformedObjectNameException; +import javax.management.ObjectName; +import java.util.*; +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 _prefetchCount; + + /** + * 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 Map _unacknowledgedMessageMap = new LinkedHashMap(DEFAULT_PREFETCH); + private UnacknowledgedMessageMap _unacknowledgedMessageMap = new UnacknowledgedMessageMapImpl(DEFAULT_PREFETCH); + + private final AtomicBoolean _suspended = new AtomicBoolean(false); + + private final MessageRouter _exchanges; + + private TransactionalContext _txnContext; + + private final List _returnMessages = new LinkedList(); + + private MessageHandleFactory _messageHandleFactory = new MessageHandleFactory(); + + public AMQChannel(int channelId, MessageStore messageStore, MessageRouter exchanges) + throws AMQException + { + _channelId = channelId; + _prefetchCount = DEFAULT_PREFETCH; + _messageStore = messageStore; + _exchanges = exchanges; + // TODO: fix me to pass in the txn context or at least have a factory for it + _txnContext = new NonTransactionalContext(_messageStore, this, _returnMessages); + } + + /** + * Sets this channel to be part of a local transaction + */ + public void setLocalTransactional() + { + _txnContext = new LocalTransactionalContext(_messageStore, new TxnBuffer(_messageStore), _returnMessages); + } + + public int getChannelId() + { + return _channelId; + } + + public long getPrefetchCount() + { + return _prefetchCount; + } + + public void setPrefetchCount(long prefetchCount) + { + _prefetchCount = prefetchCount; + } + + public void setPublishFrame(BasicPublishBody publishBody, AMQProtocolSession publisher) throws AMQException + { + _currentMessage = new AMQMessage(_messageStore.getNewMessageId(), publishBody, _txnContext); + // TODO: used in clustering only I think (RG) + //_currentMessage.setPublisher(publisher); + } + + public void publishContentHeader(ContentHeaderBody contentHeaderBody) + throws AMQException + { + if (_currentMessage == null) + { + throw new AMQException("Received content header without previously receiving a BasicPublish frame"); + } + else + { + _currentMessage.setContentHeaderBody(contentHeaderBody); + routeCurrentMessage(); + _currentMessage.routingComplete(_messageStore, _messageHandleFactory); + + // check and deliver if header says body length is zero + if (contentHeaderBody.bodySize == 0) + { + _currentMessage = null; + } + } + } + + public void publishContentBody(ContentBody contentBody) + throws AMQException + { + if (_currentMessage == null) + { + throw new AMQException("Received content body without previously receiving a JmsPublishBody"); + } + + // returns true iff the message was delivered (i.e. if all data was + // received + try + { + if (_currentMessage.addContentBodyFrame(contentBody)) + { + _currentMessage = null; + } + } + catch (AMQException e) + { + // we want to make sure we don't keep a reference to the message in the + // event of an error + _currentMessage = null; + throw e; + } + } + + protected void routeCurrentMessage() throws AMQException + { + _exchanges.routeContent(_currentMessage); + } + + /*protected void routeCurrentMessage2() 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); + } + else + { + throw new AMQException(_log, "Consumer tag " + consumerTag + " not known to channel " + + _channelId); + } + } + + /** + * 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 + } + } */ + _txnContext.rollback(); + 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 the message that was delivered + * @param deliveryTag the delivery tag used when delivering the message (see protocol spec for description of + * the delivery tag) + * @param queue the queue from which the message was delivered + */ + public void addUnacknowledgedMessage(AMQMessage message, long deliveryTag, String consumerTag, AMQQueue queue) + { + _unacknowledgedMessageMap.add(deliveryTag, new UnacknowledgedMessage(queue, message, consumerTag, 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. + * @throws org.apache.qpid.AMQException if the requeue fails + */ + 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 + Collection messagesToBeDelivered = _unacknowledgedMessageMap.cancelAllMessages(); + + for (UnacknowledgedMessage unacked : messagesToBeDelivered) + { + if (unacked.queue != null) + { + _txnContext.deliver(unacked.message, unacked.queue); + } + } + } + + /** + * Called to resend all outstanding unacknowledged messages to this same channel. + */ + public void resend(final AMQProtocolSession session) throws AMQException + { + _unacknowledgedMessageMap.visit(new UnacknowledgedMessageMap.Visitor() + { + public boolean callback(UnacknowledgedMessage message) throws AMQException + { + long deliveryTag = message.deliveryTag; + String consumerTag = message.consumerTag; + AMQMessage msg = message.message; + + msg.writeDeliver(session, _channelId, deliveryTag, consumerTag); + // false means continue processing + return false; + } + + public void visitComplete() + { + } + }); + } + + /** + * Callback indicating that a queue has been deleted. We must update the structure of unacknowledged + * messages to remove the queue reference and also decrement any message reference counts, without + * actually removing the item since we may get an ack for a delivery tag that was generated from the + * deleted queue. + * + * @param queue the queue that has been deleted + * @throws org.apache.qpid.AMQException if there is an error processing the unacked messages + */ + public void queueDeleted(final AMQQueue queue) throws AMQException + { + _unacknowledgedMessageMap.visit(new UnacknowledgedMessageMap.Visitor() + { + public boolean callback(UnacknowledgedMessage message) throws AMQException + { + if (message.queue == queue) + { + message.queue = null; + try + { + message.message.decrementReference(); + } + catch (AMQException e) + { + _log.error("Error decrementing ref count on message " + message.message.getMessageId() + ": " + + e, e); + } + } + return false; + } + + public void visitComplete() + { + } + }); + } + + /** + * 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 + { + _unacknowledgedMessageMap.acknowledgeMessage(deliveryTag, multiple, _txnContext); + checkSuspension(); + /*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); + } */ + } + + /** + * Used only for testing purposes. + * + * @return the map of unacknowledged messages + */ + public UnacknowledgedMessageMap getUnacknowledgedMessageMap() + { + return _unacknowledgedMessageMap; + } + + private void checkSuspension() + { + boolean suspend = _unacknowledgedMessageMap.size() >= _prefetchCount; + setSuspended(suspend); + } + + public void setSuspended(boolean suspended) + { + 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 + { + _txnContext.commit(); + } + + public void rollback() throws AMQException + { + _txnContext.rollback(); + } + + public String toString() + { + StringBuilder sb = new StringBuilder(30); + sb.append("Channel: id ").append(_channelId).append(", transaction context: ").append(_txnContext); + sb.append(", prefetch count: ").append(_prefetchCount); + return sb.toString(); + } + + public ObjectName getObjectName() + throws MalformedObjectNameException + { + StringBuilder sb = new StringBuilder(30); + sb.append("Channel:id=").append(_channelId); + return new ObjectName(sb.toString()); + } + + public void setDefaultQueue(AMQQueue queue) + { + _defaultQueue = queue; + } + + public AMQQueue getDefaultQueue() + { + return _defaultQueue; + } + + public void processReturns(AMQProtocolSession session) throws AMQException + { + for (RequiredDeliveryException bouncedMessage : _returnMessages) + { + AMQMessage message = bouncedMessage.getAMQMessage(); + message.writeReturn(session, _channelId, bouncedMessage.getReplyCode(), bouncedMessage.getMessage()); + } + _returnMessages.clear(); + } +} diff --git a/java/broker/main/org/apache/qpid/server/ConsumerTagNotUniqueException.java b/java/broker/main/org/apache/qpid/server/ConsumerTagNotUniqueException.java new file mode 100644 index 0000000000..6a7e54bc45 --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/ConsumerTagNotUniqueException.java @@ -0,0 +1,22 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.qpid.server; + +public class ConsumerTagNotUniqueException extends Exception +{ +} diff --git a/java/broker/main/org/apache/qpid/server/Main.java b/java/broker/main/org/apache/qpid/server/Main.java new file mode 100644 index 0000000000..13dc5fbca6 --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/Main.java @@ -0,0 +1,613 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +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.SocketAcceptorConfig; +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 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); + + 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(); + SocketAcceptorConfig sconfig = (SocketAcceptorConfig) acceptor.getDefaultConfig(); + SocketSessionConfig sc = (SocketSessionConfig) sconfig.getSessionConfig(); + + sc.setReceiveBufferSize(connectorConfig.socketReceiveBufferSize); + sc.setSendBufferSize(connectorConfig.socketWriteBuferSize); + sc.setTcpNoDelay(connectorConfig.tcpNoDelay); + + // if we do not use the executor pool threading model we get the default leader follower + // implementation provided by MINA + if (connectorConfig.enableExecutorPool) + { + sconfig.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.bind(bindAddress, handler, sconfig); + _logger.info("Qpid.AMQP listening on non-SSL address " + bindAddress); + } + + if (connectorConfig.enableSSL) + { + AMQPFastProtocolHandler handler = new AMQPProtocolProvider().getHandler(); + handler.setUseSSL(true); + try + { + acceptor.bind(new InetSocketAddress(connectorConfig.sslPort), + handler, sconfig); + _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/main/org/apache/qpid/server/ManagedChannel.java b/java/broker/main/org/apache/qpid/server/ManagedChannel.java new file mode 100644 index 0000000000..815dfdcfbd --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/ManagedChannel.java @@ -0,0 +1,64 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +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/main/org/apache/qpid/server/RequiredDeliveryException.java b/java/broker/main/org/apache/qpid/server/RequiredDeliveryException.java new file mode 100644 index 0000000000..d2b017275a --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/RequiredDeliveryException.java @@ -0,0 +1,49 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.qpid.server; + +import org.apache.qpid.AMQException; +import org.apache.qpid.server.queue.AMQMessage; + +/** + * Signals that a required delivery could not be made. This could be bacuse of + * the immediate flag being set and the queue having no consumers, or the mandatory + * flag being set and the exchange having no valid bindings. + */ +public abstract class RequiredDeliveryException extends AMQException +{ + private final AMQMessage _amqMessage; + + public RequiredDeliveryException(String message, AMQMessage payload) + { + super(message); + _amqMessage = payload; + } + + public AMQMessage getAMQMessage() + { + return _amqMessage; + } + + public int getErrorCode() + { + return getReplyCode(); + } + + public abstract int getReplyCode(); +} diff --git a/java/broker/main/org/apache/qpid/server/ack/TxAck.java b/java/broker/main/org/apache/qpid/server/ack/TxAck.java new file mode 100644 index 0000000000..85072b6976 --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/ack/TxAck.java @@ -0,0 +1,125 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.qpid.server.ack; + +import org.apache.qpid.AMQException; +import org.apache.qpid.server.txn.TxnOp; + +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/main/org/apache/qpid/server/ack/UnacknowledgedMessage.java b/java/broker/main/org/apache/qpid/server/ack/UnacknowledgedMessage.java new file mode 100644 index 0000000000..f13ecef7ac --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/ack/UnacknowledgedMessage.java @@ -0,0 +1,48 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +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/main/org/apache/qpid/server/ack/UnacknowledgedMessageMap.java b/java/broker/main/org/apache/qpid/server/ack/UnacknowledgedMessageMap.java new file mode 100644 index 0000000000..8fece7bcc1 --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/ack/UnacknowledgedMessageMap.java @@ -0,0 +1,62 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.qpid.server.ack; + +import org.apache.qpid.server.txn.TransactionalContext; +import org.apache.qpid.AMQException; + +import java.util.Collection; +import java.util.List; + +public interface UnacknowledgedMessageMap +{ + public interface Visitor + { + /** + * @param message the message being iterated over + * @return true to stop iteration, false to continue + * @throws AMQException + */ + boolean callback(UnacknowledgedMessage message) throws AMQException; + + void visitComplete(); + } + + void visit(Visitor visitor) throws AMQException; + + void add(long deliveryTag, UnacknowledgedMessage message); + + void collect(long deliveryTag, boolean multiple, List msgs); + + boolean contains(long deliveryTag) throws AMQException; + + void remove(List msgs); + + UnacknowledgedMessage remove(long deliveryTag); + + void drainTo(Collection destination, long deliveryTag) throws AMQException; + + Collection cancelAllMessages(); + + void acknowledgeMessage(long deliveryTag, boolean multiple, TransactionalContext txnContext) throws AMQException; + + int size(); + + void clear(); +} + diff --git a/java/broker/main/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java b/java/broker/main/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java new file mode 100644 index 0000000000..8061687175 --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java @@ -0,0 +1,211 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.qpid.server.ack; + +import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.txn.TransactionalContext; +import org.apache.qpid.AMQException; + +import java.util.*; + +public class UnacknowledgedMessageMapImpl implements UnacknowledgedMessageMap +{ + private final Object _lock = new Object(); + + private Map _map; + + private long _lastDeliveryTag; + + private final int _prefetchLimit; + + public UnacknowledgedMessageMapImpl(int prefetchLimit) + { + _prefetchLimit = prefetchLimit; + _map = new LinkedHashMap(prefetchLimit); + } + + /*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 boolean contains(long deliveryTag) throws AMQException + { + synchronized (_lock) + { + return _map.containsKey(deliveryTag); + } + } + + public void remove(List msgs) + { + synchronized (_lock) + { + for(UnacknowledgedMessage msg : msgs) + { + _map.remove(msg.deliveryTag); + } + } + } + + public UnacknowledgedMessage remove(long deliveryTag) + { + synchronized (_lock) + { + return _map.remove(deliveryTag); + } + } + + public void visit(Visitor visitor) throws AMQException + { + synchronized (_lock) + { + Collection currentEntries = _map.values(); + for (UnacknowledgedMessage msg: currentEntries) + { + visitor.callback(msg); + } + } + } + + public void add(long deliveryTag, UnacknowledgedMessage message) + { + synchronized( _lock) + { + _map.put(deliveryTag, message); + _lastDeliveryTag = deliveryTag; + } + } + + public Collection cancelAllMessages() + { + synchronized (_lock) + { + Collection currentEntries = _map.values(); + _map = new LinkedHashMap(_prefetchLimit); + return currentEntries; + } + } + + public void acknowledgeMessage(long deliveryTag, boolean multiple, TransactionalContext txnContext) + throws AMQException + { + synchronized (_lock) + { + txnContext.acknowledgeMessage(deliveryTag, _lastDeliveryTag, multiple, this); + } + } + + public int size() + { + synchronized (_lock) + { + return _map.size(); + } + } + + public void clear() + { + synchronized (_lock) + { + _map.clear(); + } + } + + public void drainTo(Collection destination, long deliveryTag) throws AMQException + { + synchronized (_lock) + { + Iterator> it = _map.entrySet().iterator(); + while (it.hasNext()) + { + Map.Entry unacked = it.next(); + + if (unacked.getKey() > deliveryTag) + { + //This should not occur now. + throw new AMQException("UnacknowledgedMessageMap is out of order:" + unacked.getKey() + + " When deliveryTag is:" + deliveryTag + "ES:" + _map.entrySet().toString()); + } + + it.remove(); + + destination.add(unacked.getValue()); + if (unacked.getKey() == deliveryTag) + { + break; + } + } + } + } + + public void resendMessages(AMQProtocolSession protocolSession, int channelId) throws AMQException + { + synchronized (_lock) + { + for (Map.Entry entry : _map.entrySet()) + { + long deliveryTag = entry.getKey(); + String consumerTag = entry.getValue().consumerTag; + AMQMessage msg = entry.getValue().message; + + msg.writeDeliver(protocolSession, channelId, deliveryTag, consumerTag); + } + } + } + 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/main/org/apache/qpid/server/configuration/Configurator.java b/java/broker/main/org/apache/qpid/server/configuration/Configurator.java new file mode 100644 index 0000000000..e02b958941 --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/configuration/Configurator.java @@ -0,0 +1,102 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +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/main/org/apache/qpid/server/configuration/VirtualHostConfiguration.java b/java/broker/main/org/apache/qpid/server/configuration/VirtualHostConfiguration.java new file mode 100644 index 0000000000..a7ad50917c --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/configuration/VirtualHostConfiguration.java @@ -0,0 +1,217 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +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/main/org/apache/qpid/server/exchange/AbstractExchange.java b/java/broker/main/org/apache/qpid/server/exchange/AbstractExchange.java new file mode 100644 index 0000000000..cf787b4739 --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/exchange/AbstractExchange.java @@ -0,0 +1,136 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +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/main/org/apache/qpid/server/exchange/DefaultExchangeFactory.java b/java/broker/main/org/apache/qpid/server/exchange/DefaultExchangeFactory.java new file mode 100644 index 0000000000..990a868e72 --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/exchange/DefaultExchangeFactory.java @@ -0,0 +1,63 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +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/main/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java b/java/broker/main/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java new file mode 100644 index 0000000000..62b0415253 --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java @@ -0,0 +1,93 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.qpid.server.exchange; + +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.server.protocol.ExchangeInitialiser; +import org.apache.qpid.server.queue.AMQMessage; + +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 BasicPublish being received (where the exchange is validated) and the final + // content body being received (which triggers this method) + // TODO: check where the exchange is validated + if (exch == null) + { + throw new AMQException("Exchange '" + exchange + "' does not exist"); + } + exch.route(payload); + } +} diff --git a/java/broker/main/org/apache/qpid/server/exchange/DestNameExchange.java b/java/broker/main/org/apache/qpid/server/exchange/DestNameExchange.java new file mode 100644 index 0000000000..38ceebe235 --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/exchange/DestNameExchange.java @@ -0,0 +1,219 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +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", + "Queue and binding keye", + _bindingItemNames, + _bindingItemDescriptions, + _bindingItemTypes); + _bindinglistDataType = new TabularType("Bindings", + "List of queues and binding keys", + _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 + { + final 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) + { + payload.enqueue(q); + } + } + } +} diff --git a/java/broker/main/org/apache/qpid/server/exchange/DestWildExchange.java b/java/broker/main/org/apache/qpid/server/exchange/DestWildExchange.java new file mode 100644 index 0000000000..6f38013ffb --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/exchange/DestWildExchange.java @@ -0,0 +1,223 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +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", + "Queue and binding keye", + _bindingItemNames, + _bindingItemDescriptions, + _bindingItemTypes); + _bindinglistDataType = new TabularType("Bindings", + "List of queues and binding keys", + _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 + payload.enqueue(q); + } + } + + 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/main/org/apache/qpid/server/exchange/Exchange.java b/java/broker/main/org/apache/qpid/server/exchange/Exchange.java new file mode 100644 index 0000000000..02a0badb65 --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/exchange/Exchange.java @@ -0,0 +1,47 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.qpid.server.exchange; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.queue.AMQQueue; + +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/main/org/apache/qpid/server/exchange/ExchangeFactory.java b/java/broker/main/org/apache/qpid/server/exchange/ExchangeFactory.java new file mode 100644 index 0000000000..36fd159f31 --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/exchange/ExchangeFactory.java @@ -0,0 +1,28 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +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/main/org/apache/qpid/server/exchange/ExchangeInUseException.java b/java/broker/main/org/apache/qpid/server/exchange/ExchangeInUseException.java new file mode 100644 index 0000000000..4a6c735bee --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/exchange/ExchangeInUseException.java @@ -0,0 +1,28 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +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/main/org/apache/qpid/server/exchange/ExchangeRegistry.java b/java/broker/main/org/apache/qpid/server/exchange/ExchangeRegistry.java new file mode 100644 index 0000000000..5b71cd7b0c --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/exchange/ExchangeRegistry.java @@ -0,0 +1,38 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +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/main/org/apache/qpid/server/exchange/HeadersBinding.java b/java/broker/main/org/apache/qpid/server/exchange/HeadersBinding.java new file mode 100644 index 0000000000..d69e956b5f --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/exchange/HeadersBinding.java @@ -0,0 +1,142 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +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/main/org/apache/qpid/server/exchange/HeadersExchange.java b/java/broker/main/org/apache/qpid/server/exchange/HeadersExchange.java new file mode 100644 index 0000000000..67a6ff6596 --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/exchange/HeadersExchange.java @@ -0,0 +1,239 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.qpid.server.exchange; + +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.*; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.management.MBeanDescription; +import org.apache.qpid.server.management.MBeanConstructor; + +import javax.management.openmbean.*; +import javax.management.ServiceNotFoundException; +import javax.management.NotCompliantMBeanException; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +/** + * 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 = {"Queue"}; + 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 and header attributes binding", + _bindingItemNames, + _bindingItemDescriptions, + _bindingItemTypes); + _bindinglistDataType = new TabularType("HeaderBindings", + "List of queues and related header attribute bindings", + _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; + } + + public void createBinding(String QueueName, String binding) + throws ServiceNotFoundException + { + throw new ServiceNotFoundException("This service is not supported by \"" + this.getName() + "\""); + } + + } // 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 routed = 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()); + } + payload.enqueue(e.queue); + routed = true; + } + } + if (!routed) + { + _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/main/org/apache/qpid/server/exchange/Index.java b/java/broker/main/org/apache/qpid/server/exchange/Index.java new file mode 100644 index 0000000000..9e88b6a68c --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/exchange/Index.java @@ -0,0 +1,85 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +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/main/org/apache/qpid/server/exchange/ManagedExchange.java b/java/broker/main/org/apache/qpid/server/exchange/ManagedExchange.java new file mode 100644 index 0000000000..bd02910d0a --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/exchange/ManagedExchange.java @@ -0,0 +1,90 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +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/main/org/apache/qpid/server/exchange/MessageRouter.java b/java/broker/main/org/apache/qpid/server/exchange/MessageRouter.java new file mode 100644 index 0000000000..832a60c681 --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/exchange/MessageRouter.java @@ -0,0 +1,37 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.qpid.server.exchange; + +import org.apache.qpid.AMQException; +import org.apache.qpid.server.queue.AMQMessage; + +/** + * 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/main/org/apache/qpid/server/exchange/NoRouteException.java b/java/broker/main/org/apache/qpid/server/exchange/NoRouteException.java new file mode 100644 index 0000000000..6d5511d9c8 --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/exchange/NoRouteException.java @@ -0,0 +1,39 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +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/main/org/apache/qpid/server/handler/BasicAckMethodHandler.java b/java/broker/main/org/apache/qpid/server/handler/BasicAckMethodHandler.java new file mode 100644 index 0000000000..5e236f7da9 --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/handler/BasicAckMethodHandler.java @@ -0,0 +1,52 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +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/main/org/apache/qpid/server/handler/BasicCancelMethodHandler.java b/java/broker/main/org/apache/qpid/server/handler/BasicCancelMethodHandler.java new file mode 100644 index 0000000000..52d6d9f0f1 --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/handler/BasicCancelMethodHandler.java @@ -0,0 +1,58 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +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/main/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java b/java/broker/main/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java new file mode 100644 index 0000000000..40d49815e3 --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java @@ -0,0 +1,90 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +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/main/org/apache/qpid/server/handler/BasicPublishMethodHandler.java b/java/broker/main/org/apache/qpid/server/handler/BasicPublishMethodHandler.java new file mode 100644 index 0000000000..f2f660299d --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/handler/BasicPublishMethodHandler.java @@ -0,0 +1,77 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +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/main/org/apache/qpid/server/handler/BasicQosHandler.java b/java/broker/main/org/apache/qpid/server/handler/BasicQosHandler.java new file mode 100644 index 0000000000..0d1c039207 --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/handler/BasicQosHandler.java @@ -0,0 +1,46 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +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/main/org/apache/qpid/server/handler/BasicRecoverMethodHandler.java b/java/broker/main/org/apache/qpid/server/handler/BasicRecoverMethodHandler.java new file mode 100644 index 0000000000..1dce283c9e --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/handler/BasicRecoverMethodHandler.java @@ -0,0 +1,54 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +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/main/org/apache/qpid/server/handler/ChannelCloseHandler.java b/java/broker/main/org/apache/qpid/server/handler/ChannelCloseHandler.java new file mode 100644 index 0000000000..1b03f15d22 --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/handler/ChannelCloseHandler.java @@ -0,0 +1,58 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +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/main/org/apache/qpid/server/handler/ChannelCloseOkHandler.java b/java/broker/main/org/apache/qpid/server/handler/ChannelCloseOkHandler.java new file mode 100644 index 0000000000..7731e56d4d --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/handler/ChannelCloseOkHandler.java @@ -0,0 +1,51 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +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/main/org/apache/qpid/server/handler/ChannelFlowHandler.java b/java/broker/main/org/apache/qpid/server/handler/ChannelFlowHandler.java new file mode 100644 index 0000000000..1ad917b918 --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/handler/ChannelFlowHandler.java @@ -0,0 +1,61 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +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/main/org/apache/qpid/server/handler/ChannelOpenHandler.java b/java/broker/main/org/apache/qpid/server/handler/ChannelOpenHandler.java new file mode 100644 index 0000000000..634cd70469 --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/handler/ChannelOpenHandler.java @@ -0,0 +1,58 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +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/main/org/apache/qpid/server/handler/ConnectionCloseMethodHandler.java b/java/broker/main/org/apache/qpid/server/handler/ConnectionCloseMethodHandler.java new file mode 100644 index 0000000000..f78d6f7276 --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/handler/ConnectionCloseMethodHandler.java @@ -0,0 +1,65 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +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/main/org/apache/qpid/server/handler/ConnectionCloseOkMethodHandler.java b/java/broker/main/org/apache/qpid/server/handler/ConnectionCloseOkMethodHandler.java new file mode 100644 index 0000000000..f918158edb --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/handler/ConnectionCloseOkMethodHandler.java @@ -0,0 +1,63 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +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/main/org/apache/qpid/server/handler/ConnectionOpenMethodHandler.java b/java/broker/main/org/apache/qpid/server/handler/ConnectionOpenMethodHandler.java new file mode 100644 index 0000000000..7bc28f9eb9 --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/handler/ConnectionOpenMethodHandler.java @@ -0,0 +1,68 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +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/main/org/apache/qpid/server/handler/ConnectionSecureOkMethodHandler.java b/java/broker/main/org/apache/qpid/server/handler/ConnectionSecureOkMethodHandler.java new file mode 100644 index 0000000000..1c0da4f658 --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/handler/ConnectionSecureOkMethodHandler.java @@ -0,0 +1,115 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +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/main/org/apache/qpid/server/handler/ConnectionStartOkMethodHandler.java b/java/broker/main/org/apache/qpid/server/handler/ConnectionStartOkMethodHandler.java new file mode 100644 index 0000000000..5715ce181b --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/handler/ConnectionStartOkMethodHandler.java @@ -0,0 +1,127 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +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/main/org/apache/qpid/server/handler/ConnectionTuneOkMethodHandler.java b/java/broker/main/org/apache/qpid/server/handler/ConnectionTuneOkMethodHandler.java new file mode 100644 index 0000000000..05ca10fec5 --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/handler/ConnectionTuneOkMethodHandler.java @@ -0,0 +1,54 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +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/main/org/apache/qpid/server/handler/ExchangeDeclareHandler.java b/java/broker/main/org/apache/qpid/server/handler/ExchangeDeclareHandler.java new file mode 100644 index 0000000000..444a54a4f2 --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/handler/ExchangeDeclareHandler.java @@ -0,0 +1,79 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +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/main/org/apache/qpid/server/handler/ExchangeDeleteHandler.java b/java/broker/main/org/apache/qpid/server/handler/ExchangeDeleteHandler.java new file mode 100644 index 0000000000..441e991872 --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/handler/ExchangeDeleteHandler.java @@ -0,0 +1,62 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +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/main/org/apache/qpid/server/handler/OnCurrentThreadExecutor.java b/java/broker/main/org/apache/qpid/server/handler/OnCurrentThreadExecutor.java new file mode 100644 index 0000000000..a689366a2f --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/handler/OnCurrentThreadExecutor.java @@ -0,0 +1,31 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +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/main/org/apache/qpid/server/handler/QueueBindHandler.java b/java/broker/main/org/apache/qpid/server/handler/QueueBindHandler.java new file mode 100644 index 0000000000..98eec37a4a --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/handler/QueueBindHandler.java @@ -0,0 +1,94 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +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/main/org/apache/qpid/server/handler/QueueDeclareHandler.java b/java/broker/main/org/apache/qpid/server/handler/QueueDeclareHandler.java new file mode 100644 index 0000000000..d1eb387748 --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/handler/QueueDeclareHandler.java @@ -0,0 +1,124 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +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/main/org/apache/qpid/server/handler/QueueDeleteHandler.java b/java/broker/main/org/apache/qpid/server/handler/QueueDeleteHandler.java new file mode 100644 index 0000000000..82c1d93065 --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/handler/QueueDeleteHandler.java @@ -0,0 +1,84 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +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/main/org/apache/qpid/server/handler/TxCommitHandler.java b/java/broker/main/org/apache/qpid/server/handler/TxCommitHandler.java new file mode 100644 index 0000000000..14399b08f0 --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/handler/TxCommitHandler.java @@ -0,0 +1,61 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +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/main/org/apache/qpid/server/handler/TxRollbackHandler.java b/java/broker/main/org/apache/qpid/server/handler/TxRollbackHandler.java new file mode 100644 index 0000000000..ff2d79fb95 --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/handler/TxRollbackHandler.java @@ -0,0 +1,59 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +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/main/org/apache/qpid/server/handler/TxSelectHandler.java b/java/broker/main/org/apache/qpid/server/handler/TxSelectHandler.java new file mode 100644 index 0000000000..cf665950ca --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/handler/TxSelectHandler.java @@ -0,0 +1,50 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +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()).setLocalTransactional(); + protocolSession.writeFrame(TxSelectOkBody.createAMQFrame(evt.getChannelId())); + } +} diff --git a/java/broker/main/org/apache/qpid/server/jms/JmsConsumer.java b/java/broker/main/org/apache/qpid/server/jms/JmsConsumer.java new file mode 100644 index 0000000000..da82d2166e --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/jms/JmsConsumer.java @@ -0,0 +1,107 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +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/main/org/apache/qpid/server/management/AMQManagedObject.java b/java/broker/main/org/apache/qpid/server/management/AMQManagedObject.java new file mode 100644 index 0000000000..a5733ed4ef --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/management/AMQManagedObject.java @@ -0,0 +1,94 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +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/main/org/apache/qpid/server/management/DefaultManagedObject.java b/java/broker/main/org/apache/qpid/server/management/DefaultManagedObject.java new file mode 100644 index 0000000000..cd0d58acdb --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/management/DefaultManagedObject.java @@ -0,0 +1,168 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +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/main/org/apache/qpid/server/management/JMXManagedObjectRegistry.java b/java/broker/main/org/apache/qpid/server/management/JMXManagedObjectRegistry.java new file mode 100644 index 0000000000..0cd43cecac --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/management/JMXManagedObjectRegistry.java @@ -0,0 +1,49 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +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/main/org/apache/qpid/server/management/MBeanAttribute.java b/java/broker/main/org/apache/qpid/server/management/MBeanAttribute.java new file mode 100644 index 0000000000..595c97dd76 --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/management/MBeanAttribute.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; +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +/** + * 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/main/org/apache/qpid/server/management/MBeanConstructor.java b/java/broker/main/org/apache/qpid/server/management/MBeanConstructor.java new file mode 100644 index 0000000000..2ce275d50d --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/management/MBeanConstructor.java @@ -0,0 +1,37 @@ +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; +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +/** + * 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/main/org/apache/qpid/server/management/MBeanDescription.java b/java/broker/main/org/apache/qpid/server/management/MBeanDescription.java new file mode 100644 index 0000000000..ef6993036f --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/management/MBeanDescription.java @@ -0,0 +1,36 @@ +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; +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +/** + * 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/main/org/apache/qpid/server/management/MBeanIntrospector.java b/java/broker/main/org/apache/qpid/server/management/MBeanIntrospector.java new file mode 100644 index 0000000000..dcf05fa6fe --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/management/MBeanIntrospector.java @@ -0,0 +1,385 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +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/main/org/apache/qpid/server/management/MBeanOperation.java b/java/broker/main/org/apache/qpid/server/management/MBeanOperation.java new file mode 100644 index 0000000000..30fdf81eee --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/management/MBeanOperation.java @@ -0,0 +1,40 @@ +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; +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +/** + * 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/main/org/apache/qpid/server/management/MBeanOperationParameter.java b/java/broker/main/org/apache/qpid/server/management/MBeanOperationParameter.java new file mode 100644 index 0000000000..919ac767c7 --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/management/MBeanOperationParameter.java @@ -0,0 +1,35 @@ +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; +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +/** + * 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/main/org/apache/qpid/server/management/Managable.java b/java/broker/main/org/apache/qpid/server/management/Managable.java new file mode 100644 index 0000000000..e62e1c7f87 --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/management/Managable.java @@ -0,0 +1,31 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +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/main/org/apache/qpid/server/management/ManagedBroker.java b/java/broker/main/org/apache/qpid/server/management/ManagedBroker.java new file mode 100644 index 0000000000..a38931a0d8 --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/management/ManagedBroker.java @@ -0,0 +1,95 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +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/main/org/apache/qpid/server/management/ManagedObject.java b/java/broker/main/org/apache/qpid/server/management/ManagedObject.java new file mode 100644 index 0000000000..4007337173 --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/management/ManagedObject.java @@ -0,0 +1,55 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +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/main/org/apache/qpid/server/management/ManagedObjectRegistry.java b/java/broker/main/org/apache/qpid/server/management/ManagedObjectRegistry.java new file mode 100644 index 0000000000..7270ec83b4 --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/management/ManagedObjectRegistry.java @@ -0,0 +1,39 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +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/main/org/apache/qpid/server/management/ManagementConfiguration.java b/java/broker/main/org/apache/qpid/server/management/ManagementConfiguration.java new file mode 100644 index 0000000000..ec80009d17 --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/management/ManagementConfiguration.java @@ -0,0 +1,27 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +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/main/org/apache/qpid/server/management/NoopManagedObjectRegistry.java b/java/broker/main/org/apache/qpid/server/management/NoopManagedObjectRegistry.java new file mode 100644 index 0000000000..3bf2c8d9ca --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/management/NoopManagedObjectRegistry.java @@ -0,0 +1,45 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +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/main/org/apache/qpid/server/protocol/AMQMethodEvent.java b/java/broker/main/org/apache/qpid/server/protocol/AMQMethodEvent.java new file mode 100644 index 0000000000..0c8d049951 --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/protocol/AMQMethodEvent.java @@ -0,0 +1,62 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +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/main/org/apache/qpid/server/protocol/AMQMethodListener.java b/java/broker/main/org/apache/qpid/server/protocol/AMQMethodListener.java new file mode 100644 index 0000000000..e8d973cd91 --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/protocol/AMQMethodListener.java @@ -0,0 +1,52 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +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/main/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java b/java/broker/main/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java new file mode 100644 index 0000000000..9ede6157f4 --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java @@ -0,0 +1,681 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +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.*; +import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.exchange.ExchangeRegistry; +import org.apache.qpid.server.management.*; +import org.apache.qpid.server.queue.QueueRegistry; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.state.AMQStateManager; + +import javax.management.*; +import javax.management.monitor.MonitorNotification; +import javax.management.openmbean.*; +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; + + /* 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", + "ChannelName", + "Transactional", + "DefaultQueue", + "UnacknowledgedMessageCount"}; + private String[] _channelAttributeDescriptions = { "Channel Identifier", + "Channel Name", + "is Channel Transactional?", + "Default Queue Name", + "Unacknowledged Message Count"}; + private OpenType[] _channelAttributeTypes = { SimpleType.INTEGER, + SimpleType.OBJECTNAME, + SimpleType.BOOLEAN, + SimpleType.STRING, + SimpleType.INTEGER}; + /** + * Channels in the list will be indexed according to channelId. + */ + private String[] _indexNames = { "ChannelId" }; + + /** + * represents the data type for channel data. + */ + private CompositeType _channelType = null; + /** + * Datatype for list of channelsType. + */ + private TabularType _channelsType = null; + + 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", + "a Channel", + _channelAtttibuteNames, + _channelAttributeDescriptions, + _channelAttributeTypes); + + _channelsType = new TabularType("channelsType", + "List of available channelsType", + _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"); + } + 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"); + } + 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(); + //ManagedChannel channel = (AMQChannelMBean)amqChannel.getManagedObject(); + ObjectName channelObjectName = null; + + try + { + channelObjectName = channel.getObjectName(); + } + catch (MalformedObjectNameException ex) + { + _logger.error("Unable to create object name: ", ex); + } + + Object[] itemValues = {channel.getChannelId(), + channelObjectName, + (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 + { + contentFrameReceived(frame); + } + } + } + + 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().writeDeliver(). + * + * @param frame the frame to writeDeliver + */ + 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/main/org/apache/qpid/server/protocol/AMQPFastProtocolHandler.java b/java/broker/main/org/apache/qpid/server/protocol/AMQPFastProtocolHandler.java new file mode 100644 index 0000000000..78fb76ae27 --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/protocol/AMQPFastProtocolHandler.java @@ -0,0 +1,227 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +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)) + { + //writeDeliver 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/main/org/apache/qpid/server/protocol/AMQPProtocolProvider.java b/java/broker/main/org/apache/qpid/server/protocol/AMQPProtocolProvider.java new file mode 100644 index 0000000000..0088db08bb --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/protocol/AMQPProtocolProvider.java @@ -0,0 +1,50 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +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/main/org/apache/qpid/server/protocol/AMQProtocolSession.java b/java/broker/main/org/apache/qpid/server/protocol/AMQProtocolSession.java new file mode 100644 index 0000000000..402ebc329d --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/protocol/AMQProtocolSession.java @@ -0,0 +1,122 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +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/main/org/apache/qpid/server/protocol/ExchangeInitialiser.java b/java/broker/main/org/apache/qpid/server/protocol/ExchangeInitialiser.java new file mode 100644 index 0000000000..08c31ed3ff --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/protocol/ExchangeInitialiser.java @@ -0,0 +1,38 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +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/main/org/apache/qpid/server/protocol/HeartbeatConfig.java b/java/broker/main/org/apache/qpid/server/protocol/HeartbeatConfig.java new file mode 100644 index 0000000000..d7678185d4 --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/protocol/HeartbeatConfig.java @@ -0,0 +1,64 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +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/main/org/apache/qpid/server/protocol/ManagedConnection.java b/java/broker/main/org/apache/qpid/server/protocol/ManagedConnection.java new file mode 100644 index 0000000000..2a800f327d --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/protocol/ManagedConnection.java @@ -0,0 +1,138 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +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. + */ + @MBeanAttribute(name="MaximumNumberOfAllowedChannels", + description="The maximum number of channels that can be opened using this connection") + Long getMaximumNumberOfAllowedChannels(); + + /** + * Sets the maximum number of channels allowed to be created using + * this connection. + * @param value + */ + 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/main/org/apache/qpid/server/protocol/ManagedSession.java b/java/broker/main/org/apache/qpid/server/protocol/ManagedSession.java new file mode 100644 index 0000000000..2a1a0b62c2 --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/protocol/ManagedSession.java @@ -0,0 +1,33 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.qpid.server.protocol; + +import java.util.Date; + +public interface ManagedSession +{ + static final String TYPE = "Connection"; + + Date getLastIoTime(); + + String getRemoteAddress(); + + long getWrittenBytes(); + + long getReadBytes(); +} diff --git a/java/broker/main/org/apache/qpid/server/queue/AMQMessage.java b/java/broker/main/org/apache/qpid/server/queue/AMQMessage.java new file mode 100644 index 0000000000..afab90dcc4 --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/queue/AMQMessage.java @@ -0,0 +1,520 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.qpid.server.queue; + +import org.apache.mina.common.ByteBuffer; +import org.apache.qpid.AMQException; +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.TransactionalContext; +import org.apache.log4j.Logger; + +import java.util.*; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * Combines the information that make up a deliverable message into a more manageable form. + */ +public class AMQMessage +{ + private static final Logger _log = Logger.getLogger(AMQMessage.class); + + /** + * Used in clustering + */ + private final Set _tokens = new HashSet(); + + /** + * Used in clustering + * TODO need to get rid of this + */ + private AMQProtocolSession _publisher; + + private final long _messageId; + + private final AtomicInteger _referenceCount = new AtomicInteger(1); + + private AMQMessageHandle _messageHandle; + + /** + * Stored temporarily until the header has been received at which point it is used when + * constructing the handle + */ + private BasicPublishBody _publishBody; + + /** + * Also stored temporarily. + */ + private ContentHeaderBody _contentHeaderBody; + + /** + * Keeps a track of how many bytes we have received in body frames + */ + private long _bodyLengthReceived = 0; + + private final TransactionalContext _txnContext; + + /** + * 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; + + /** + * This is stored during routing, to know the queues to which this message should immediately be + * delivered. It is cleared after delivery has been attempted. Any persistent record of destinations is done + * by the message handle. + */ + private List _destinationQueues = new LinkedList(); + + /** + * Used to iterate through all the body frames associated with this message. Will not + * keep all the data in memory therefore is memory-efficient. + */ + private class BodyFrameIterator implements Iterator + { + private int _channel; + + private int _index = -1; + + private BodyFrameIterator(int channel) + { + _channel = channel; + } + + public boolean hasNext() + { + return _index < _messageHandle.getBodyCount() - 1; + } + + public AMQDataBlock next() + { + try + { + ContentBody cb = _messageHandle.getContentBody(_messageId, ++_index); + return ContentBody.createAMQFrame(_channel, cb); + } + catch (AMQException e) + { + // have no choice but to throw a runtime exception + throw new RuntimeException("Error getting content body: " + e, e); + } + + } + + public void remove() + { + throw new UnsupportedOperationException(); + } + } + + private class BodyContentIterator implements Iterator + { + + private int _index = -1; + + public boolean hasNext() + { + return _index < _messageHandle.getBodyCount() - 1; + } + + public ContentBody next() + { + try + { + return _messageHandle.getContentBody(_messageId, ++_index); + } + catch (AMQException e) + { + throw new RuntimeException("Error getting content body: " + e, e); + } + } + + public void remove() + { + throw new UnsupportedOperationException(); + } + } + + public AMQMessage(long messageId, BasicPublishBody publishBody, TransactionalContext txnContext) + { + _messageId = messageId; + _txnContext = txnContext; + _publishBody = publishBody; + if (_log.isDebugEnabled()) + { + _log.debug("Message created with id " + messageId); + } + } + + protected AMQMessage(AMQMessage msg) throws AMQException + { + _publisher = msg._publisher; + _messageId = msg._messageId; + _messageHandle = msg._messageHandle; + _txnContext = msg._txnContext; + _deliveredToConsumer = msg._deliveredToConsumer; + } + + public Iterator getBodyFrameIterator(int channel) + { + return new BodyFrameIterator(channel); + } + + public Iterator getContentBodyIterator() + { + return new BodyContentIterator(); + } + + public ContentHeaderBody getContentHeaderBody() throws AMQException + { + return _messageHandle.getContentHeaderBody(_messageId); + } + + public void setContentHeaderBody(ContentHeaderBody contentHeaderBody) + throws AMQException + { + _contentHeaderBody = contentHeaderBody; + } + + public void routingComplete(MessageStore store, MessageHandleFactory factory) throws AMQException + { + final boolean persistent = isPersistent(); + _messageHandle = factory.createMessageHandle(_messageId, store, persistent); + if (persistent) + { + _txnContext.beginTranIfNecessary(); + } + + // enqueuing the messages ensure that if required the destinations are recorded to a + // persistent store + for (AMQQueue q : _destinationQueues) + { + _messageHandle.enqueue(_messageId, q); + } + + if (_contentHeaderBody.bodySize == 0) + { + deliver(); + } + } + + public boolean addContentBodyFrame(ContentBody contentBody) throws AMQException + { + _bodyLengthReceived += contentBody.getSize(); + _messageHandle.addContentBodyFrame(_messageId, contentBody); + if (isAllContentReceived()) + { + deliver(); + return true; + } + else + { + return false; + } + } + + public boolean isAllContentReceived() throws AMQException + { + return _bodyLengthReceived == _contentHeaderBody.bodySize; + } + + public long getMessageId() + { + return _messageId; + } + + /** + * Threadsafe. Increment the reference count on the message. + */ + public void incrementReference() + { + _referenceCount.incrementAndGet(); + if (_log.isDebugEnabled()) + { + _log.debug("Ref count on message " + _messageId + " incremented to " + _referenceCount); + } + } + + /** + * Threadsafe. This will decrement the reference count and when it reaches zero will remove the message from the + * message store. + * + * @throws MessageCleanupException when an attempt was made to remove the message from the message store and that + * failed + */ + 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 + { + if (_log.isDebugEnabled()) + { + _log.debug("Ref count on message " + _messageId + " is zero; removing message"); + } + _messageHandle.removeMessage(_messageId); + } + catch (AMQException e) + { + //to maintain consistency, we revert the count + incrementReference(); + throw new MessageCleanupException(_messageId, e); + } + } + else + { + if (_log.isDebugEnabled()) + { + _log.debug("Ref count is now " + _referenceCount + " for message id " + _messageId); + if (_referenceCount.get() < 0) + { + Thread.dumpStack(); + } + } + } + } + + 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; + } + } + + /** + * Registers a queue to which this message is to be delivered. This is + * called from the exchange when it is routing the message. This will be called before any content bodies have + * been received so that the choice of AMQMessageHandle implementation can be picked based on various criteria. + * + * @param queue the queue + * @throws org.apache.qpid.AMQException if there is an error enqueuing the message + */ + public void enqueue(AMQQueue queue) throws AMQException + { + _destinationQueues.add(queue); + } + + public void dequeue(AMQQueue queue) throws AMQException + { + _messageHandle.dequeue(_messageId, queue); + } + + public boolean isPersistent() throws AMQException + { + if (_contentHeaderBody != null) + { + //todo remove literal values to a constant file such as AMQConstants in common + return _contentHeaderBody.properties instanceof BasicContentHeaderProperties && + ((BasicContentHeaderProperties) _contentHeaderBody.properties).getDeliveryMode() == 2; + } + else + { + return _messageHandle.isPersistent(_messageId); + } + } + + /** + * 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, AMQException + { + BasicPublishBody pb = getPublishBody(); + if (pb.immediate && !_deliveredToConsumer) + { + throw new NoConsumersException(this); + } + } + + public BasicPublishBody getPublishBody() throws AMQException + { + BasicPublishBody pb; + if (_publishBody != null) + { + pb = _publishBody; + } + else + { + pb = _messageHandle.getPublishBody(_messageId); + } + return pb; + } + + /** + * Called when this message is delivered to a consumer. (used to + * implement the 'immediate' flag functionality). + */ + public void setDeliveredToConsumer() + { + _deliveredToConsumer = true; + } + + /*public void registerQueue(AMQQueue queue) + { + _destinationQueues.add(queue); + } */ + + private void deliver() throws AMQException + { + // first we allow the handle to know that the message has been fully received. This is useful if it is + // maintaining any calculated values based on content chunks + try + { + _messageHandle.setPublishAndContentHeaderBody(_messageId, _publishBody, _contentHeaderBody); + _publishBody = null; + _contentHeaderBody = null; + + // we then allow the transactional context to do something with the message content + // now that it has all been received, before we attempt delivery + _txnContext.messageFullyReceived(isPersistent()); + for (AMQQueue q : _destinationQueues) + { + _txnContext.deliver(this, q); + } + } + finally + { + _destinationQueues.clear(); + _destinationQueues = null; + decrementReference(); + } + } + + public void writeDeliver(AMQProtocolSession protocolSession, int channelId, long deliveryTag, String consumerTag) + throws AMQException + { + ByteBuffer deliver = createEncodedDeliverFrame(channelId, deliveryTag, consumerTag); + AMQDataBlock contentHeader = ContentHeaderBody.createAMQFrame(channelId, + getContentHeaderBody()); + + Iterator bodyFrameIterator = getBodyFrameIterator(channelId); + // + // Optimise the case where we have a single content body. In that case we create a composite block + // so that we can writeDeliver out the deliver, header and body with a single network writeDeliver. + // + if (bodyFrameIterator.hasNext()) + { + AMQDataBlock firstContentBody = bodyFrameIterator.next(); + AMQDataBlock[] headerAndFirstContent = new AMQDataBlock[]{contentHeader, firstContentBody}; + CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(deliver, headerAndFirstContent); + protocolSession.writeFrame(compositeBlock); + } + else + { + CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(deliver, + new AMQDataBlock[]{contentHeader}); + protocolSession.writeFrame(compositeBlock); + } + + // + // Now start writing out the other content bodies + // TODO: MINA needs to be fixed so the the pending writes buffer is not unbounded + // + while (bodyFrameIterator.hasNext()) + { + protocolSession.writeFrame(bodyFrameIterator.next()); + } + + } + + private ByteBuffer createEncodedDeliverFrame(int channelId, long deliveryTag, String consumerTag) + throws AMQException + { + BasicPublishBody pb = getPublishBody(); + AMQFrame deliverFrame = BasicDeliverBody.createAMQFrame(channelId, consumerTag, + deliveryTag, false, pb.exchange, + pb.routingKey); + ByteBuffer buf = ByteBuffer.allocate((int) deliverFrame.getSize()); // XXX: Could cast be a problem? + deliverFrame.writePayload(buf); + buf.flip(); + return buf; + } + + private ByteBuffer createEncodedReturnFrame(int channelId, int replyCode, String replyText) + { + AMQFrame returnFrame = BasicReturnBody.createAMQFrame(channelId, replyCode, replyText, _publishBody.exchange, + _publishBody.routingKey); + ByteBuffer buf = ByteBuffer.allocate((int) returnFrame.getSize()); // XXX: Could cast be a problem? + returnFrame.writePayload(buf); + buf.flip(); + return buf; + } + + public void writeReturn(AMQProtocolSession protocolSession, int channelId, int replyCode, String replyText) + throws AMQException + { + ByteBuffer returnFrame = createEncodedReturnFrame(channelId, replyCode, replyText); + + AMQDataBlock contentHeader = ContentHeaderBody.createAMQFrame(channelId, + getContentHeaderBody()); + + Iterator bodyFrameIterator = getBodyFrameIterator(channelId); + // + // Optimise the case where we have a single content body. In that case we create a composite block + // so that we can writeDeliver out the deliver, header and body with a single network writeDeliver. + // + if (bodyFrameIterator.hasNext()) + { + AMQDataBlock firstContentBody = bodyFrameIterator.next(); + AMQDataBlock[] headerAndFirstContent = new AMQDataBlock[]{contentHeader, firstContentBody}; + CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(returnFrame, headerAndFirstContent); + protocolSession.writeFrame(compositeBlock); + } + else + { + CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(returnFrame, + new AMQDataBlock[]{contentHeader}); + protocolSession.writeFrame(compositeBlock); + } + + // + // Now start writing out the other content bodies + // TODO: MINA needs to be fixed so the the pending writes buffer is not unbounded + // + while (bodyFrameIterator.hasNext()) + { + protocolSession.writeFrame(bodyFrameIterator.next()); + } + } +} diff --git a/java/broker/main/org/apache/qpid/server/queue/AMQMessageHandle.java b/java/broker/main/org/apache/qpid/server/queue/AMQMessageHandle.java new file mode 100644 index 0000000000..0fc9ec5dcd --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/queue/AMQMessageHandle.java @@ -0,0 +1,62 @@ +/** + * User: Robert Greig + * Date: 23-Oct-2006 + ****************************************************************************** + * (c) Copyright JP Morgan Chase Ltd 2006. All rights reserved. No part of + * this program may be photocopied reproduced or translated to another + * program language without prior written consent of JP Morgan Chase Ltd + ******************************************************************************/ +package org.apache.qpid.server.queue; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.BasicPublishBody; +import org.apache.qpid.framing.ContentBody; +import org.apache.qpid.framing.ContentHeaderBody; + +/** + * A pluggable way of getting message data. Implementations can provide intelligent caching for example or + * even no caching at all to minimise the broker memory footprint. + * + * The method all take a messageId to avoid having to store it in the instance - the AMQMessage container + * must already keen the messageId so it is pointless storing it twice. + */ +public interface AMQMessageHandle +{ + ContentHeaderBody getContentHeaderBody(long messageId) throws AMQException; + + /** + * @return the number of body frames associated with this message + */ + int getBodyCount(); + + /** + * @return the size of the body + */ + long getBodySize(long messageId) throws AMQException; + + /** + * Get a particular content body + * @param index the index of the body to retrieve, must be between 0 and getBodyCount() - 1 + * @return a content body + * @throws IllegalArgumentException if the index is invalid + */ + ContentBody getContentBody(long messageId, int index) throws IllegalArgumentException, AMQException; + + void addContentBodyFrame(long messageId, ContentBody contentBody) throws AMQException; + + BasicPublishBody getPublishBody(long messageId) throws AMQException; + + boolean isRedelivered(); + + boolean isPersistent(long messageId) throws AMQException; + + void setPublishAndContentHeaderBody(long messageId, BasicPublishBody publishBody, + ContentHeaderBody contentHeaderBody) + throws AMQException; + + void removeMessage(long messageId) throws AMQException; + + void enqueue(long messageId, AMQQueue queue) throws AMQException; + + void dequeue(long messageId, AMQQueue queue) throws AMQException; +} \ No newline at end of file diff --git a/java/broker/main/org/apache/qpid/server/queue/AMQQueue.java b/java/broker/main/org/apache/qpid/server/queue/AMQQueue.java new file mode 100644 index 0000000000..d8bab6e3bc --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/queue/AMQQueue.java @@ -0,0 +1,764 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.qpid.server.queue; + +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.ContentBody; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.management.*; +import org.apache.qpid.server.protocol.AMQProtocolSession; + +import javax.management.*; +import javax.management.monitor.MonitorNotification; +import javax.management.openmbean.*; +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.Iterator; +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; + //private MBeanInfo _mbeanInfo; + + // AMQ message attribute names exposed. + private String[] _msgAttributeNames = { "MessageId", + "Redelivered", + "Content's size", + "Contents" }; + // AMQ Message attribute descriptions. + private String[] _msgAttributeDescriptions = { "Message Id", + "Redelivered", + "Message content's size in bytes", + "Message content bodies" }; + // AMQ message attribute types. + private OpenType[] _msgAttributeTypes = new OpenType[4]; + // Messages will be indexed according to the messageId. + private String[] _msgAttributeIndex = { "MessageId"}; + // Composite type for representing AMQ Message data. + private CompositeType _messageDataType = null; + // Datatype for representing AMQ messages list. + private TabularType _messagelistDataType = null; + + private String[] _contentNames = {"SerialNumber", "ContentBody"}; + private String[] _contentDesc = {"SerialNumber", "Message Content"}; + private String[] _contentIndex = {"SerialNumber"}; + private OpenType[] _contentType = new OpenType[2]; + private CompositeType _contentBodyType = null; + private TabularType _contentBodyListType = null; + + @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 + { + _contentType[0] = SimpleType.INTEGER; + _contentType[1] = new ArrayType(1, SimpleType.BYTE); + _contentBodyType = new CompositeType("Content", + "Message body content", + _contentNames, + _contentDesc, + _contentType); + _contentBodyListType = new TabularType("MessageContents", + "MessageContent", + _contentBodyType, + _contentIndex); + + _msgAttributeTypes[0] = SimpleType.LONG; + _msgAttributeTypes[1] = SimpleType.BOOLEAN; + _msgAttributeTypes[2] = SimpleType.LONG; + _msgAttributeTypes[3] = _contentBodyListType; + + _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() throws AMQException + { + List list = _deliveryMgr.getMessages(); + if (list.size() == 0) + return 0l; + + long queueSize = 0; + for (AMQMessage message : list) + { + queueSize = queueSize + getMessageSize(message); + } + return (long) Math.round(queueSize/100); + } + // Operations + + // calculates the size of an AMQMessage + private long getMessageSize(AMQMessage msg) throws AMQException + { + if (msg == null) + { + return 0L; + } + + return msg.getContentHeaderBody().bodySize; + } + + // Checks if there is any notification to be send to the listeners + private void checkForNotification(AMQMessage msg) throws AMQException + { + // 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()); + } + } + + /** + * 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(); + + if (beginIndex > list.size()) + { + throw new JMException("FromIndex = " + beginIndex + ". There are only " + list.size() + + " messages in the queue"); + } + + endIndex = endIndex < list.size() ? endIndex : list.size(); + TabularDataSupport _messageList = new TabularDataSupport(_messagelistDataType); + + for (int i = beginIndex; i <= endIndex; i++) + { + AMQMessage msg = list.get(i - 1); + long msgId = msg.getMessageId(); + + Iterator cBodies = msg.getContentBodyIterator(); + + TabularDataSupport _contentList = new TabularDataSupport(_contentBodyListType); + int contentSerialNo = 1; + long size = 0; + + while (cBodies.hasNext()) + { + ContentBody body = cBodies.next(); + if (body.getSize() != 0) + { + Byte[] byteArray = getByteArray(body.payload.slice().array()); + size = size + byteArray.length; + + Object[] contentValues = {contentSerialNo, byteArray}; + CompositeData contentData = new CompositeDataSupport(_contentBodyType, + _contentNames, + contentValues); + + _contentList.put(contentData); + } + } + + Object[] itemValues = {msgId, true, size, _contentList}; + CompositeData messageData = new CompositeDataSupport(_messageDataType, + _msgAttributeNames, + itemValues); + _messageList.put(messageData); + } + + return _messageList; + } + + /** + * A utility to convert byte[] to Byte[]. Required to create composite + * type for message contents. + * @param byteArray message content as byte[] + * @return Byte[] + */ + private Byte[] getByteArray(byte[] byteArray) + { + int size = byteArray.length; + List list = new ArrayList(); + + for (int i = 0; i < size; i++) + { + list.add(byteArray[i]); + } + + return list.toArray(new Byte[0]); + } + + /** + * 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; + _deliveryMgr = new DeliveryManager(_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.getQueueMessageCount() > 0) + { + _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(); + } */ + + public void process(AMQMessage msg) throws FailedDequeueException, AMQException + { + _deliveryMgr.deliver(getName(), msg); + updateReceivedMessageCount(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) throws AMQException + { + _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)); + } + } +} diff --git a/java/broker/main/org/apache/qpid/server/queue/AsyncDeliveryConfig.java b/java/broker/main/org/apache/qpid/server/queue/AsyncDeliveryConfig.java new file mode 100644 index 0000000000..60788c1ccb --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/queue/AsyncDeliveryConfig.java @@ -0,0 +1,53 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +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/main/org/apache/qpid/server/queue/DefaultQueueRegistry.java b/java/broker/main/org/apache/qpid/server/queue/DefaultQueueRegistry.java new file mode 100644 index 0000000000..a7dc98ec22 --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/queue/DefaultQueueRegistry.java @@ -0,0 +1,47 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +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/main/org/apache/qpid/server/queue/DeliveryManager.java b/java/broker/main/org/apache/qpid/server/queue/DeliveryManager.java new file mode 100644 index 0000000000..55ecf799f6 --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/queue/DeliveryManager.java @@ -0,0 +1,259 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +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 DeliveryManager +{ + private static final Logger _log = Logger.getLogger(DeliveryManager.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 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; + + DeliveryManager(SubscriptionManager subscriptions, AMQQueue queue) + { + _subscriptions = subscriptions; + _queue = queue; + } + + private synchronized boolean enqueue(AMQMessage msg) throws AMQException + { + if (_queueing) + { + if(msg.getPublishBody().immediate) + { + //can't enqueue messages for whom immediate delivery is required + return false; + } + else + { + _messages.offer(msg); + return true; + } + } + else + { + return false; + } + } + + private synchronized void startQueueing(AMQMessage msg) throws AMQException + { + _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 + */ + private synchronized boolean hasQueuedMessages() + { + boolean empty = _messages.isEmpty(); + if (empty) + { + _queueing = false; + } + return !empty; + } + + public synchronized int getQueueMessageCount() + { + return _messages.size(); + } + + protected synchronized List getMessages() + { + return new ArrayList(_messages); + } + + protected synchronized void removeAMessageFromTop() throws AMQException + { + AMQMessage msg = poll(); + if (msg != null) + { + msg.dequeue(_queue); + } + } + + protected 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(). + * @throws org.apache.qpid.AMQException if we cannot process the messages on the queue + */ + private void processQueue() throws AMQException + { + 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) + { + next.send(poll(), _queue); + } + else + { + hasSubscribers = false; + } + } + } + catch (FailedDequeueException e) + { + _log.error("Unable to deliver message as dequeue failed: " + e, e); + } + 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 + */ + 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 + * @throws FailedDequeueException if the message could not be dequeued + */ + void deliver(String name, AMQMessage msg) throws FailedDequeueException, AMQException + { + // first check whether we are queueing, and enqueue if we are + if (!enqueue(msg)) + { + // not queueing so deliver message to 'next' subscriber + Subscription s = _subscriptions.nextSubscriber(msg); + if (s == null) + { + if (!msg.getPublishBody().immediate) + { + // 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() + { + try + { + processQueue(); + } + catch (AMQException e) + { + _log.error("Error processing queue: " + e, e); + } + } + } +} diff --git a/java/broker/main/org/apache/qpid/server/queue/ExchangeBindings.java b/java/broker/main/org/apache/qpid/server/queue/ExchangeBindings.java new file mode 100644 index 0000000000..424330bd11 --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/queue/ExchangeBindings.java @@ -0,0 +1,109 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +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/main/org/apache/qpid/server/queue/FailedDequeueException.java b/java/broker/main/org/apache/qpid/server/queue/FailedDequeueException.java new file mode 100644 index 0000000000..f27d935c25 --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/queue/FailedDequeueException.java @@ -0,0 +1,36 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +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/main/org/apache/qpid/server/queue/InMemoryMessageHandle.java b/java/broker/main/org/apache/qpid/server/queue/InMemoryMessageHandle.java new file mode 100644 index 0000000000..e2e334c5f4 --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/queue/InMemoryMessageHandle.java @@ -0,0 +1,110 @@ +/** + * User: Robert Greig + * Date: 21-Nov-2006 + ****************************************************************************** + * (c) Copyright JP Morgan Chase Ltd 2006. All rights reserved. No part of + * this program may be photocopied reproduced or translated to another + * program language without prior written consent of JP Morgan Chase Ltd + ******************************************************************************/ +package org.apache.qpid.server.queue; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.BasicContentHeaderProperties; +import org.apache.qpid.framing.BasicPublishBody; +import org.apache.qpid.framing.ContentBody; +import org.apache.qpid.framing.ContentHeaderBody; + +import java.util.LinkedList; +import java.util.List; + +/** + */ +public class InMemoryMessageHandle implements AMQMessageHandle +{ + + private ContentHeaderBody _contentHeaderBody; + + private BasicPublishBody _publishBody; + + private List _contentBodies = new LinkedList(); + + private boolean _redelivered; + + public InMemoryMessageHandle() + { + } + + public ContentHeaderBody getContentHeaderBody(long messageId) throws AMQException + { + return _contentHeaderBody; + } + + public int getBodyCount() + { + return _contentBodies.size(); + } + + public long getBodySize(long messageId) throws AMQException + { + return getContentHeaderBody(messageId).bodySize; + } + + public ContentBody getContentBody(long messageId, int index) throws AMQException, IllegalArgumentException + { + if (index > _contentBodies.size() - 1) + { + throw new IllegalArgumentException("Index " + index + " out of valid range 0 to " + + (_contentBodies.size() - 1)); + } + return _contentBodies.get(index); + } + + public void addContentBodyFrame(long messageId, ContentBody contentBody) throws AMQException + { + _contentBodies.add(contentBody); + } + + public BasicPublishBody getPublishBody(long messageId) throws AMQException + { + return _publishBody; + } + + public boolean isRedelivered() + { + return _redelivered; + } + + public boolean isPersistent(long messageId) throws AMQException + { + //todo remove literal values to a constant file such as AMQConstants in common + ContentHeaderBody chb = getContentHeaderBody(messageId); + return chb.properties instanceof BasicContentHeaderProperties && + ((BasicContentHeaderProperties) chb.properties).getDeliveryMode() == 2; + } + + /** + * This is called when all the content has been received. + * @param publishBody + * @param contentHeaderBody + * @throws AMQException + */ + public void setPublishAndContentHeaderBody(long messageId, BasicPublishBody publishBody, + ContentHeaderBody contentHeaderBody) + throws AMQException + { + _publishBody = publishBody; + _contentHeaderBody = contentHeaderBody; + } + + public void removeMessage(long messageId) throws AMQException + { + } + + public void enqueue(long messageId, AMQQueue queue) throws AMQException + { + } + + public void dequeue(long messageId, AMQQueue queue) throws AMQException + { + } +} diff --git a/java/broker/main/org/apache/qpid/server/queue/ManagedQueue.java b/java/broker/main/org/apache/qpid/server/queue/ManagedQueue.java new file mode 100644 index 0000000000..7528011bac --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/queue/ManagedQueue.java @@ -0,0 +1,213 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +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 org.apache.qpid.AMQException; + +import javax.management.JMException; +import javax.management.MBeanOperationInfo; +import javax.management.openmbean.TabularData; +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, AMQException; + + /** + * 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; + +} diff --git a/java/broker/main/org/apache/qpid/server/queue/MessageCleanupException.java b/java/broker/main/org/apache/qpid/server/queue/MessageCleanupException.java new file mode 100644 index 0000000000..6f0fa285b1 --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/queue/MessageCleanupException.java @@ -0,0 +1,32 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +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/main/org/apache/qpid/server/queue/MessageHandleFactory.java b/java/broker/main/org/apache/qpid/server/queue/MessageHandleFactory.java new file mode 100644 index 0000000000..93aceb76ec --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/queue/MessageHandleFactory.java @@ -0,0 +1,34 @@ +/** + * User: Robert Greig + * Date: 31-Oct-2006 + ****************************************************************************** + * (c) Copyright JP Morgan Chase Ltd 2006. All rights reserved. No part of + * this program may be photocopied reproduced or translated to another + * program language without prior written consent of JP Morgan Chase Ltd + ******************************************************************************/ +package org.apache.qpid.server.queue; + +import org.apache.qpid.server.store.MessageStore; + +/** + * Constructs a message handle based on the publish body, the content header and the queue to which the message + * has been routed. + * + * @author Robert Greig (robert.j.greig@jpmorgan.com) + */ +public class MessageHandleFactory +{ + + public AMQMessageHandle createMessageHandle(long messageId, MessageStore store, boolean persistent) + { + // just hardcoded for now + if (persistent) + { + return new WeakReferenceMessageHandle(store); + } + else + { + return new InMemoryMessageHandle(); + } + } +} diff --git a/java/broker/main/org/apache/qpid/server/queue/MessageMetaData.java b/java/broker/main/org/apache/qpid/server/queue/MessageMetaData.java new file mode 100644 index 0000000000..deed18c188 --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/queue/MessageMetaData.java @@ -0,0 +1,70 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.qpid.server.queue; + +import org.apache.qpid.framing.BasicPublishBody; +import org.apache.qpid.framing.ContentHeaderBody; + +/** + * Encapsulates a publish body and a content header. In the context of the message store these are treated as a + * single unit. + */ +public class MessageMetaData +{ + private BasicPublishBody _publishBody; + + private ContentHeaderBody _contentHeaderBody; + + private int _contentChunkCount; + + public MessageMetaData(BasicPublishBody publishBody, ContentHeaderBody contentHeaderBody, int contentChunkCount) + { + _contentHeaderBody = contentHeaderBody; + _publishBody = publishBody; + _contentChunkCount = contentChunkCount; + } + + public int getContentChunkCount() + { + return _contentChunkCount; + } + + public void setContentChunkCount(int contentChunkCount) + { + _contentChunkCount = contentChunkCount; + } + + public ContentHeaderBody getContentHeaderBody() + { + return _contentHeaderBody; + } + + public void setContentHeaderBody(ContentHeaderBody contentHeaderBody) + { + _contentHeaderBody = contentHeaderBody; + } + + public BasicPublishBody getPublishBody() + { + return _publishBody; + } + + public void setPublishBody(BasicPublishBody publishBody) + { + _publishBody = publishBody; + } +} diff --git a/java/broker/main/org/apache/qpid/server/queue/NoConsumersException.java b/java/broker/main/org/apache/qpid/server/queue/NoConsumersException.java new file mode 100644 index 0000000000..09f01d6d97 --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/queue/NoConsumersException.java @@ -0,0 +1,39 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.qpid.server.queue; + +import org.apache.qpid.protocol.AMQConstant; +import org.apache.qpid.server.RequiredDeliveryException; + +/** + * 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(AMQMessage message) + { + super("Immediate delivery is not possible.", message); + } + + public int getReplyCode() + { + return AMQConstant.NO_CONSUMERS.getCode(); + } +} diff --git a/java/broker/main/org/apache/qpid/server/queue/QueueRegistry.java b/java/broker/main/org/apache/qpid/server/queue/QueueRegistry.java new file mode 100644 index 0000000000..bc5599fb20 --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/queue/QueueRegistry.java @@ -0,0 +1,30 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +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/main/org/apache/qpid/server/queue/Subscription.java b/java/broker/main/org/apache/qpid/server/queue/Subscription.java new file mode 100644 index 0000000000..a248efecb1 --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/queue/Subscription.java @@ -0,0 +1,29 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.qpid.server.queue; + +import org.apache.qpid.AMQException; + +public interface Subscription +{ + void send(AMQMessage msg, AMQQueue queue) throws AMQException; + + boolean isSuspended(); + + void queueDeleted(AMQQueue queue) throws AMQException; +} diff --git a/java/broker/main/org/apache/qpid/server/queue/SubscriptionFactory.java b/java/broker/main/org/apache/qpid/server/queue/SubscriptionFactory.java new file mode 100644 index 0000000000..127b19b0e4 --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/queue/SubscriptionFactory.java @@ -0,0 +1,37 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +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/main/org/apache/qpid/server/queue/SubscriptionImpl.java b/java/broker/main/org/apache/qpid/server/queue/SubscriptionImpl.java new file mode 100644 index 0000000000..4422d1ffc2 --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/queue/SubscriptionImpl.java @@ -0,0 +1,170 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.qpid.server.queue; + +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +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 AMQException + { + 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); + } + + msg.writeDeliver(protocolSession, channel.getChannelId(), deliveryTag, consumerTag); + } + } + 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) throws AMQException + { + channel.queueDeleted(queue); + } +} diff --git a/java/broker/main/org/apache/qpid/server/queue/SubscriptionManager.java b/java/broker/main/org/apache/qpid/server/queue/SubscriptionManager.java new file mode 100644 index 0000000000..185b0e4268 --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/queue/SubscriptionManager.java @@ -0,0 +1,28 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +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/main/org/apache/qpid/server/queue/SubscriptionSet.java b/java/broker/main/org/apache/qpid/server/queue/SubscriptionSet.java new file mode 100644 index 0000000000..fe55bd071b --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/queue/SubscriptionSet.java @@ -0,0 +1,182 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.qpid.server.queue; + +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; + +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) throws AMQException + { + for (Subscription s : _subscriptions) + { + s.queueDeleted(queue); + } + } + + int size() { + return _subscriptions.size(); + } +} diff --git a/java/broker/main/org/apache/qpid/server/queue/WeakReferenceMessageHandle.java b/java/broker/main/org/apache/qpid/server/queue/WeakReferenceMessageHandle.java new file mode 100644 index 0000000000..bf82940ec8 --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/queue/WeakReferenceMessageHandle.java @@ -0,0 +1,144 @@ +/** + * User: Robert Greig + * Date: 23-Oct-2006 + ****************************************************************************** + * (c) Copyright JP Morgan Chase Ltd 2006. All rights reserved. No part of + * this program may be photocopied reproduced or translated to another + * program language without prior written consent of JP Morgan Chase Ltd + ******************************************************************************/ +package org.apache.qpid.server.queue; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.BasicContentHeaderProperties; +import org.apache.qpid.framing.BasicPublishBody; +import org.apache.qpid.framing.ContentBody; +import org.apache.qpid.framing.ContentHeaderBody; +import org.apache.qpid.server.store.MessageStore; + +import java.lang.ref.WeakReference; +import java.util.LinkedList; +import java.util.List; + +/** + * @author Robert Greig (robert.j.greig@jpmorgan.com) + */ +public class WeakReferenceMessageHandle implements AMQMessageHandle +{ + private WeakReference _contentHeaderBody; + + private WeakReference _publishBody; + + private List> _contentBodies = new LinkedList>(); + + private boolean _redelivered; + + private final MessageStore _messageStore; + + public WeakReferenceMessageHandle(MessageStore messageStore) + { + _messageStore = messageStore; + } + + public ContentHeaderBody getContentHeaderBody(long messageId) throws AMQException + { + ContentHeaderBody chb = _contentHeaderBody.get(); + if (chb == null) + { + MessageMetaData mmd = _messageStore.getMessageMetaData(messageId); + chb = mmd.getContentHeaderBody(); + _contentHeaderBody = new WeakReference(chb); + _publishBody = new WeakReference(mmd.getPublishBody()); + } + return chb; + } + + public int getBodyCount() + { + return _contentBodies.size(); + } + + public long getBodySize(long messageId) throws AMQException + { + return getContentHeaderBody(messageId).bodySize; + } + + public ContentBody getContentBody(long messageId, int index) throws AMQException, IllegalArgumentException + { + if (index > _contentBodies.size() - 1) + { + throw new IllegalArgumentException("Index " + index + " out of valid range 0 to " + + (_contentBodies.size() - 1)); + } + WeakReference wr = _contentBodies.get(index); + ContentBody cb = wr.get(); + if (cb == null) + { + cb = _messageStore.getContentBodyChunk(messageId, index); + _contentBodies.set(index, new WeakReference(cb)); + } + return cb; + } + + public void addContentBodyFrame(long messageId, ContentBody contentBody) throws AMQException + { + _contentBodies.add(new WeakReference(contentBody)); + _messageStore.storeContentBodyChunk(messageId, _contentBodies.size() - 1, contentBody); + } + + public BasicPublishBody getPublishBody(long messageId) throws AMQException + { + BasicPublishBody bpb = _publishBody.get(); + if (bpb == null) + { + MessageMetaData mmd = _messageStore.getMessageMetaData(messageId); + bpb = mmd.getPublishBody(); + _publishBody = new WeakReference(bpb); + _contentHeaderBody = new WeakReference(mmd.getContentHeaderBody()); + } + return bpb; + } + + public boolean isRedelivered() + { + return _redelivered; + } + + public boolean isPersistent(long messageId) throws AMQException + { + //todo remove literal values to a constant file such as AMQConstants in common + ContentHeaderBody chb = getContentHeaderBody(messageId); + return chb.properties instanceof BasicContentHeaderProperties && + ((BasicContentHeaderProperties) chb.properties).getDeliveryMode() == 2; + } + + /** + * This is called when all the content has been received. + * @param publishBody + * @param contentHeaderBody + * @throws AMQException + */ + public void setPublishAndContentHeaderBody(long messageId, BasicPublishBody publishBody, + ContentHeaderBody contentHeaderBody) + throws AMQException + { + _messageStore.storeMessageMetaData(messageId, new MessageMetaData(publishBody, contentHeaderBody, + _contentBodies.size())); + _publishBody = new WeakReference(publishBody); + _contentHeaderBody = new WeakReference(contentHeaderBody); + } + + public void removeMessage(long messageId) throws AMQException + { + _messageStore.removeMessage(messageId); + } + + public void enqueue(long messageId, AMQQueue queue) throws AMQException + { + _messageStore.enqueueMessage(queue.getName(), messageId); + } + + public void dequeue(long messageId, AMQQueue queue) throws AMQException + { + _messageStore.dequeueMessage(queue.getName(), messageId); + } +} diff --git a/java/broker/main/org/apache/qpid/server/queue/WeightedSubscriptionManager.java b/java/broker/main/org/apache/qpid/server/queue/WeightedSubscriptionManager.java new file mode 100644 index 0000000000..adf6aefdfb --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/queue/WeightedSubscriptionManager.java @@ -0,0 +1,23 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.qpid.server.queue; + +public interface WeightedSubscriptionManager extends SubscriptionManager +{ + public int getWeight(); +} diff --git a/java/broker/main/org/apache/qpid/server/registry/ApplicationRegistry.java b/java/broker/main/org/apache/qpid/server/registry/ApplicationRegistry.java new file mode 100644 index 0000000000..50f3d711ab --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/registry/ApplicationRegistry.java @@ -0,0 +1,197 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +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/main/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java b/java/broker/main/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java new file mode 100644 index 0000000000..db79ae8876 --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java @@ -0,0 +1,155 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +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/main/org/apache/qpid/server/registry/IApplicationRegistry.java b/java/broker/main/org/apache/qpid/server/registry/IApplicationRegistry.java new file mode 100644 index 0000000000..0102f78424 --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/registry/IApplicationRegistry.java @@ -0,0 +1,65 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +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/main/org/apache/qpid/server/security/auth/AuthenticationManager.java b/java/broker/main/org/apache/qpid/server/security/auth/AuthenticationManager.java new file mode 100644 index 0000000000..0adb7b98e2 --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/security/auth/AuthenticationManager.java @@ -0,0 +1,30 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +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/main/org/apache/qpid/server/security/auth/AuthenticationProviderInitialiser.java b/java/broker/main/org/apache/qpid/server/security/auth/AuthenticationProviderInitialiser.java new file mode 100644 index 0000000000..71e3c81ae4 --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/security/auth/AuthenticationProviderInitialiser.java @@ -0,0 +1,63 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +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/main/org/apache/qpid/server/security/auth/AuthenticationResult.java b/java/broker/main/org/apache/qpid/server/security/auth/AuthenticationResult.java new file mode 100644 index 0000000000..d7dcf2c973 --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/security/auth/AuthenticationResult.java @@ -0,0 +1,40 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +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/main/org/apache/qpid/server/security/auth/CRAMMD5Initialiser.java b/java/broker/main/org/apache/qpid/server/security/auth/CRAMMD5Initialiser.java new file mode 100644 index 0000000000..bfd2ac1b9f --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/security/auth/CRAMMD5Initialiser.java @@ -0,0 +1,35 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +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/main/org/apache/qpid/server/security/auth/JCAProvider.java b/java/broker/main/org/apache/qpid/server/security/auth/JCAProvider.java new file mode 100644 index 0000000000..1477b33ebe --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/security/auth/JCAProvider.java @@ -0,0 +1,43 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +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/main/org/apache/qpid/server/security/auth/NullAuthenticationManager.java b/java/broker/main/org/apache/qpid/server/security/auth/NullAuthenticationManager.java new file mode 100644 index 0000000000..95a53951ad --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/security/auth/NullAuthenticationManager.java @@ -0,0 +1,82 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +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/main/org/apache/qpid/server/security/auth/PasswordFilePrincipalDatabase.java b/java/broker/main/org/apache/qpid/server/security/auth/PasswordFilePrincipalDatabase.java new file mode 100644 index 0000000000..fb11b89367 --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/security/auth/PasswordFilePrincipalDatabase.java @@ -0,0 +1,130 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +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/main/org/apache/qpid/server/security/auth/PrincipalDatabase.java b/java/broker/main/org/apache/qpid/server/security/auth/PrincipalDatabase.java new file mode 100644 index 0000000000..8add5455ee --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/security/auth/PrincipalDatabase.java @@ -0,0 +1,42 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +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/main/org/apache/qpid/server/security/auth/SASLAuthenticationManager.java b/java/broker/main/org/apache/qpid/server/security/auth/SASLAuthenticationManager.java new file mode 100644 index 0000000000..7d0b60d95e --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/security/auth/SASLAuthenticationManager.java @@ -0,0 +1,224 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +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/main/org/apache/qpid/server/security/auth/UsernamePasswordInitialiser.java b/java/broker/main/org/apache/qpid/server/security/auth/UsernamePasswordInitialiser.java new file mode 100644 index 0000000000..02a953f47c --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/security/auth/UsernamePasswordInitialiser.java @@ -0,0 +1,99 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +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/main/org/apache/qpid/server/security/auth/UsernamePrincipal.java b/java/broker/main/org/apache/qpid/server/security/auth/UsernamePrincipal.java new file mode 100644 index 0000000000..1d425b8399 --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/security/auth/UsernamePrincipal.java @@ -0,0 +1,39 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +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/main/org/apache/qpid/server/security/auth/amqplain/AmqPlainInitialiser.java b/java/broker/main/org/apache/qpid/server/security/auth/amqplain/AmqPlainInitialiser.java new file mode 100644 index 0000000000..94406237a5 --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/security/auth/amqplain/AmqPlainInitialiser.java @@ -0,0 +1,35 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +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/main/org/apache/qpid/server/security/auth/amqplain/AmqPlainSaslServer.java b/java/broker/main/org/apache/qpid/server/security/auth/amqplain/AmqPlainSaslServer.java new file mode 100644 index 0000000000..0f7981abe1 --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/security/auth/amqplain/AmqPlainSaslServer.java @@ -0,0 +1,120 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +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/main/org/apache/qpid/server/security/auth/amqplain/AmqPlainSaslServerFactory.java b/java/broker/main/org/apache/qpid/server/security/auth/amqplain/AmqPlainSaslServerFactory.java new file mode 100644 index 0000000000..c4e904f923 --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/security/auth/amqplain/AmqPlainSaslServerFactory.java @@ -0,0 +1,56 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +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/main/org/apache/qpid/server/security/auth/plain/PlainInitialiser.java b/java/broker/main/org/apache/qpid/server/security/auth/plain/PlainInitialiser.java new file mode 100644 index 0000000000..7b055a4f58 --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/security/auth/plain/PlainInitialiser.java @@ -0,0 +1,35 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +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/main/org/apache/qpid/server/security/auth/plain/PlainSaslServer.java b/java/broker/main/org/apache/qpid/server/security/auth/plain/PlainSaslServer.java new file mode 100644 index 0000000000..5a69ed02ba --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/security/auth/plain/PlainSaslServer.java @@ -0,0 +1,141 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +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/main/org/apache/qpid/server/security/auth/plain/PlainSaslServerFactory.java b/java/broker/main/org/apache/qpid/server/security/auth/plain/PlainSaslServerFactory.java new file mode 100644 index 0000000000..754ecbde78 --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/security/auth/plain/PlainSaslServerFactory.java @@ -0,0 +1,56 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +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/main/org/apache/qpid/server/state/AMQState.java b/java/broker/main/org/apache/qpid/server/state/AMQState.java new file mode 100644 index 0000000000..46d46eb4c0 --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/state/AMQState.java @@ -0,0 +1,33 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +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/main/org/apache/qpid/server/state/AMQStateManager.java b/java/broker/main/org/apache/qpid/server/state/AMQStateManager.java new file mode 100644 index 0000000000..54c8bcd9d5 --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/state/AMQStateManager.java @@ -0,0 +1,219 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +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/main/org/apache/qpid/server/state/IllegalStateTransitionException.java b/java/broker/main/org/apache/qpid/server/state/IllegalStateTransitionException.java new file mode 100644 index 0000000000..c77cb4f833 --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/state/IllegalStateTransitionException.java @@ -0,0 +1,45 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +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/main/org/apache/qpid/server/state/StateAwareMethodListener.java b/java/broker/main/org/apache/qpid/server/state/StateAwareMethodListener.java new file mode 100644 index 0000000000..9776151c28 --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/state/StateAwareMethodListener.java @@ -0,0 +1,37 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +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/main/org/apache/qpid/server/state/StateListener.java b/java/broker/main/org/apache/qpid/server/state/StateListener.java new file mode 100644 index 0000000000..d31e786ef1 --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/state/StateListener.java @@ -0,0 +1,27 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +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/main/org/apache/qpid/server/store/MemoryMessageStore.java b/java/broker/main/org/apache/qpid/server/store/MemoryMessageStore.java new file mode 100644 index 0000000000..0a243fa138 --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/store/MemoryMessageStore.java @@ -0,0 +1,172 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.qpid.server.store; + +import org.apache.commons.configuration.Configuration; +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.ContentBody; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.queue.MessageMetaData; +import org.apache.qpid.server.queue.QueueRegistry; + +import java.util.ArrayList; +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 _metaDataMap; + + protected ConcurrentMap> _contentBodyMap; + + private final AtomicLong _messageId = new AtomicLong(1); + + public void configure() + { + _log.info("Using capacity " + DEFAULT_HASHTABLE_CAPACITY + " for hash tables"); + _metaDataMap = new ConcurrentHashMap(DEFAULT_HASHTABLE_CAPACITY); + _contentBodyMap = 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 tables"); + _metaDataMap = new ConcurrentHashMap(hashtableCapacity); + _contentBodyMap = new ConcurrentHashMap>(hashtableCapacity); + } + + public void configure(QueueRegistry queueRegistry, String base, Configuration config) throws Exception + { + configure(base, config); + } + + public void close() throws Exception + { + if (_metaDataMap != null) + { + _metaDataMap.clear(); + _metaDataMap = null; + } + if (_contentBodyMap != null) + { + _contentBodyMap.clear(); + _contentBodyMap = null; + } + } + + public void removeMessage(long messageId) + { + if (_log.isDebugEnabled()) + { + _log.debug("Removing message with id " + messageId); + } + _metaDataMap.remove(messageId); + _contentBodyMap.remove(messageId); + } + + public void createQueue(AMQQueue queue) throws AMQException + { + // Not required to do anything + } + + public void removeQueue(String name) throws AMQException + { + // Not required to do anything + } + + public void enqueueMessage(String name, long messageId) throws AMQException + { + // Not required to do anything + } + + public void dequeueMessage(String name, long messageId) throws AMQException + { + // Not required to do anything + } + + public void beginTran() throws AMQException + { + // Not required to do anything + } + + public void commitTran() throws AMQException + { + // Not required to do anything + } + + public void abortTran() throws AMQException + { + // Not required to do anything + } + + public boolean inTran() + { + return false; + } + + public List createQueues() throws AMQException + { + return null; + } + + public long getNewMessageId() + { + return _messageId.getAndIncrement(); + } + + public void storeContentBodyChunk(long messageId, int index, ContentBody contentBody) throws AMQException + { + List bodyList = _contentBodyMap.get(messageId); + if (bodyList == null) + { + bodyList = new ArrayList(); + _contentBodyMap.put(messageId, bodyList); + } + + bodyList.add(index, contentBody); + } + + public void storeMessageMetaData(long messageId, MessageMetaData messageMetaData) throws AMQException + { + _metaDataMap.put(messageId, messageMetaData); + } + + public MessageMetaData getMessageMetaData(long messageId) throws AMQException + { + return _metaDataMap.get(messageId); + } + + public ContentBody getContentBodyChunk(long messageId, int index) throws AMQException + { + List bodyList = _contentBodyMap.get(messageId); + return bodyList.get(index); + } +} diff --git a/java/broker/main/org/apache/qpid/server/store/MessageStore.java b/java/broker/main/org/apache/qpid/server/store/MessageStore.java new file mode 100644 index 0000000000..c0e8d0465b --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/store/MessageStore.java @@ -0,0 +1,87 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.qpid.server.store; + +import org.apache.commons.configuration.Configuration; +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.ContentBody; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.queue.MessageMetaData; +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 + * @throws Exception if an error occurs that means the store is unable to configure itself + */ + void configure(QueueRegistry queueRegistry, String base, Configuration config) throws Exception; + + /** + * Called to close and cleanup any resources used by the message store. + * @throws Exception if close fails + */ + void close() throws Exception; + + 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(); + + void storeContentBodyChunk(long messageId, int index, ContentBody contentBody) throws AMQException; + + void storeMessageMetaData(long messageId, MessageMetaData messageMetaData) throws AMQException; + + MessageMetaData getMessageMetaData(long messageId) throws AMQException; + + ContentBody getContentBodyChunk(long messageId, int index) throws AMQException; + +} diff --git a/java/broker/main/org/apache/qpid/server/transport/ConnectorConfiguration.java b/java/broker/main/org/apache/qpid/server/transport/ConnectorConfiguration.java new file mode 100644 index 0000000000..6470d876bb --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/transport/ConnectorConfiguration.java @@ -0,0 +1,83 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +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/main/org/apache/qpid/server/transport/ThreadPoolFilter.java b/java/broker/main/org/apache/qpid/server/transport/ThreadPoolFilter.java new file mode 100644 index 0000000000..e3d87f808c --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/transport/ThreadPoolFilter.java @@ -0,0 +1,692 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +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/main/org/apache/qpid/server/txn/CleanupMessageOperation.java b/java/broker/main/org/apache/qpid/server/txn/CleanupMessageOperation.java new file mode 100644 index 0000000000..7ff609b750 --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/txn/CleanupMessageOperation.java @@ -0,0 +1,89 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.qpid.server.txn; + +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.queue.NoConsumersException; +import org.apache.qpid.server.RequiredDeliveryException; + +import java.util.List; + +/** + * @author Apache Software Foundation + */ +public class CleanupMessageOperation implements TxnOp +{ + private static final Logger _log = Logger.getLogger(CleanupMessageOperation.class); + + private final AMQMessage _msg; + + private final List _returns; + + public CleanupMessageOperation(AMQMessage msg, List returns) + { + _msg = msg; + _returns = returns; + } + + 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); + } + catch (AMQException e) + { + _log.error("On commiting transaction, unable to determine whether delivered to a consumer immediately: " + + e, e); + } + } + + public void rollback() + { + } +} diff --git a/java/broker/main/org/apache/qpid/server/txn/DeliverMessageOperation.java b/java/broker/main/org/apache/qpid/server/txn/DeliverMessageOperation.java new file mode 100644 index 0000000000..059c13c687 --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/txn/DeliverMessageOperation.java @@ -0,0 +1,61 @@ +/** + * User: Robert Greig + * Date: 01-Nov-2006 + ****************************************************************************** + * (c) Copyright JP Morgan Chase Ltd 2006. All rights reserved. No part of + * this program may be photocopied reproduced or translated to another + * program language without prior written consent of JP Morgan Chase Ltd + ******************************************************************************/ +package org.apache.qpid.server.txn; + +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.queue.AMQQueue; + +/** + * @author Robert Greig (robert.j.greig@jpmorgan.com) + */ +public class DeliverMessageOperation implements TxnOp +{ + private static final Logger _logger = Logger.getLogger(DeliverMessageOperation.class); + + private final AMQMessage _msg; + + private final AMQQueue _queue; + + public DeliverMessageOperation(AMQMessage msg, AMQQueue queue) + { + _msg = msg; + _queue = queue; + _msg.incrementReference(); + } + + public void prepare() throws AMQException + { + } + + public void undoPrepare() + { + } + + public void commit() + { + //do the memeory part of the record() + _msg.incrementReference(); + //then process the message + try + { + _queue.process(_msg); + } + catch (AMQException 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/main/org/apache/qpid/server/txn/LocalTransactionalContext.java b/java/broker/main/org/apache/qpid/server/txn/LocalTransactionalContext.java new file mode 100644 index 0000000000..df6520e0a8 --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/txn/LocalTransactionalContext.java @@ -0,0 +1,149 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.qpid.server.txn; + +import org.apache.qpid.AMQException; +import org.apache.qpid.server.ack.TxAck; +import org.apache.qpid.server.ack.UnacknowledgedMessageMap; +import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.RequiredDeliveryException; +import org.apache.qpid.server.store.MessageStore; + +import java.util.List; + +/** + * A transactional context that only supports local transactions. + */ +public class LocalTransactionalContext implements TransactionalContext +{ + private final TxnBuffer _txnBuffer; + + /** + * We keep hold of the ack operation so that we can consolidate acks, i.e. multiple acks within a txn are + * consolidated into a single operation + */ + private TxAck _ackOp; + + private List _returnMessages; + + private final MessageStore _messageStore; + + private boolean _inTran = false; + + public LocalTransactionalContext(MessageStore messageStore, + TxnBuffer txnBuffer, List returnMessages) + { + _messageStore = messageStore; + _txnBuffer = txnBuffer; + _returnMessages = returnMessages; + _txnBuffer.enlist(new StoreMessageOperation(messageStore)); + } + + public void rollback() throws AMQException + { + _txnBuffer.rollback(); + } + + public void deliver(AMQMessage message, AMQQueue queue) throws AMQException + { + // don't create a transaction unless needed + if (message.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. + + _txnBuffer.enlist(new DeliverMessageOperation(message, queue)); + _txnBuffer.enlist(new CleanupMessageOperation(message, _returnMessages)); + } + + private void checkAck(long deliveryTag, UnacknowledgedMessageMap unacknowledgedMessageMap) throws AMQException + { + if (!unacknowledgedMessageMap.contains(deliveryTag)) + { + throw new AMQException("Ack with delivery tag " + deliveryTag + " not known for channel"); + } + } + + public void acknowledgeMessage(long deliveryTag, long lastDeliveryTag, boolean multiple, + UnacknowledgedMessageMap unacknowledgedMessageMap) throws AMQException + { + //check that the tag exists to give early failure + if (!multiple || deliveryTag > 0) + { + checkAck(deliveryTag, unacknowledgedMessageMap); + } + //we use a single txn op for all acks and update this op + //as new acks come in. If this is the first ack in the txn + //we will need to create and enlist the op. + if (_ackOp == null) + { + _ackOp = new TxAck(unacknowledgedMessageMap); + _txnBuffer.enlist(_ackOp); + } + // update the op to include this ack request + if (multiple && deliveryTag == 0) + { + // if have signalled to ack all, that refers only + // to all at this time + _ackOp.update(lastDeliveryTag, multiple); + } + else + { + _ackOp.update(deliveryTag, multiple); + } + } + + public void messageFullyReceived(boolean persistent) throws AMQException + { + // Not required in this transactional context + } + + public void beginTranIfNecessary() throws AMQException + { + if (!_inTran) + { + _messageStore.beginTran(); + _inTran = true; + } + } + + public void commit() throws AMQException + { + if (_ackOp != null) + { + _ackOp.consolidate(); + if (_ackOp.checkPersistent()) + { + _txnBuffer.containsPersistentChanges(); + } + //already enlisted, after commit will reset regardless of outcome + _ackOp = null; + } + + _txnBuffer.commit(); + //TODO: may need to return 'immediate' messages at this point + } +} diff --git a/java/broker/main/org/apache/qpid/server/txn/NonTransactionalContext.java b/java/broker/main/org/apache/qpid/server/txn/NonTransactionalContext.java new file mode 100644 index 0000000000..9c8e7c7002 --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/txn/NonTransactionalContext.java @@ -0,0 +1,171 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.qpid.server.txn; + +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.RequiredDeliveryException; +import org.apache.qpid.server.ack.UnacknowledgedMessage; +import org.apache.qpid.server.ack.UnacknowledgedMessageMap; +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 java.util.LinkedList; +import java.util.List; + +/** + * @author Apache Software Foundation + */ +public class NonTransactionalContext implements TransactionalContext +{ + private static final Logger _log = Logger.getLogger(NonTransactionalContext.class); + + /** + * Channel is useful for logging + */ + private final AMQChannel _channel; + + /** + * Where to put undeliverable messages + */ + private final List _returnMessages; + + private final MessageStore _messageStore; + + /** + * Whether we are in a transaction + */ + private boolean _inTran; + + public NonTransactionalContext(MessageStore messageStore, AMQChannel channel, + List returnMessages) + { + _channel = channel; + _returnMessages = returnMessages; + _messageStore = messageStore; + } + + public void beginTranIfNecessary() throws AMQException + { + if (!_inTran) + { + _messageStore.beginTran(); + _inTran = true; + } + } + + public void commit() throws AMQException + { + // Does not apply to this context + } + + public void rollback() throws AMQException + { + // Does not apply to this context + } + + public void deliver(AMQMessage message, AMQQueue queue) throws AMQException + { + try + { + message.incrementReference(); + queue.process(message); + //following check implements the functionality + //required by the 'immediate' flag: + message.checkDeliveredToConsumer(); + } + catch (NoConsumersException e) + { + _returnMessages.add(e); + } + } + + public void acknowledgeMessage(final long deliveryTag, long lastDeliveryTag, + boolean multiple, final UnacknowledgedMessageMap unacknowledgedMessageMap) + throws AMQException + { + if (multiple) + { + if (deliveryTag == 0) + { + + //Spec 2.1.6.11 ... If the multiple field is 1, and the delivery tag is zero, + // tells the server to acknowledge all outstanding mesages. + _log.info("Multiple ack on delivery tag 0. ACKing all messages. Current count:" + + unacknowledgedMessageMap.size()); + unacknowledgedMessageMap.visit(new UnacknowledgedMessageMap.Visitor() + { + public boolean callback(UnacknowledgedMessage message) throws AMQException + { + message.discard(); + return false; + } + + public void visitComplete() + { + unacknowledgedMessageMap.clear(); + } + }); + } + else + { + if (!unacknowledgedMessageMap.contains(deliveryTag)) + { + throw new AMQException("Multiple ack on delivery tag " + deliveryTag + " not known for channel"); + } + + LinkedList acked = new LinkedList(); + unacknowledgedMessageMap.drainTo(acked, deliveryTag); + for (UnacknowledgedMessage msg : acked) + { + msg.discard(); + } + } + } + else + { + UnacknowledgedMessage msg; + msg = unacknowledgedMessageMap.remove(deliveryTag); + + if (msg == null) + { + _log.info("Single ack on delivery tag " + deliveryTag + " not known for channel:" + + _channel.getChannelId()); + throw new AMQException("Single ack on delivery tag " + deliveryTag + " not known for channel:" + + _channel.getChannelId()); + } + msg.discard(); + if (_log.isDebugEnabled()) + { + _log.debug("Received non-multiple ack for messaging with delivery tag " + deliveryTag); + } + } + } + + public void messageFullyReceived(boolean persistent) throws AMQException + { + if (persistent) + { + _messageStore.commitTran(); + _inTran = false; + } + } +} diff --git a/java/broker/main/org/apache/qpid/server/txn/StoreMessageOperation.java b/java/broker/main/org/apache/qpid/server/txn/StoreMessageOperation.java new file mode 100644 index 0000000000..2a3b524060 --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/txn/StoreMessageOperation.java @@ -0,0 +1,45 @@ +/** + * User: Robert Greig + * Date: 01-Nov-2006 + ****************************************************************************** + * (c) Copyright JP Morgan Chase Ltd 2006. All rights reserved. No part of + * this program may be photocopied reproduced or translated to another + * program language without prior written consent of JP Morgan Chase Ltd + ******************************************************************************/ +package org.apache.qpid.server.txn; + +import org.apache.qpid.AMQException; +import org.apache.qpid.server.store.MessageStore; + +/** + * A transactional operation to store messages in an underlying persistent store. When this operation + * commits it will do everything to ensure that all messages are safely committed to persistent + * storage. + */ +public class StoreMessageOperation implements TxnOp +{ + private final MessageStore _messsageStore; + + public StoreMessageOperation(MessageStore messageStore) + { + _messsageStore = messageStore; + } + + public void prepare() throws AMQException + { + } + + public void undoPrepare() + { + } + + public void commit() throws AMQException + { + _messsageStore.commitTran(); + } + + public void rollback() throws AMQException + { + _messsageStore.abortTran(); + } +} diff --git a/java/broker/main/org/apache/qpid/server/txn/TransactionalContext.java b/java/broker/main/org/apache/qpid/server/txn/TransactionalContext.java new file mode 100644 index 0000000000..1ec216cc8b --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/txn/TransactionalContext.java @@ -0,0 +1,33 @@ +/** + * User: Robert Greig + * Date: 01-Nov-2006 + ****************************************************************************** + * (c) Copyright JP Morgan Chase Ltd 2006. All rights reserved. No part of + * this program may be photocopied reproduced or translated to another + * program language without prior written consent of JP Morgan Chase Ltd + ******************************************************************************/ +package org.apache.qpid.server.txn; + +import org.apache.qpid.AMQException; +import org.apache.qpid.server.ack.UnacknowledgedMessageMap; +import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.queue.AMQQueue; + +/** + * @author Robert Greig (robert.j.greig@jpmorgan.com) + */ +public interface TransactionalContext +{ + void beginTranIfNecessary() throws AMQException; + + void commit() throws AMQException; + + void rollback() throws AMQException; + + void deliver(AMQMessage message, AMQQueue queue) throws AMQException; + + void acknowledgeMessage(long deliveryTag, long lastDeliveryTag, boolean multiple, + UnacknowledgedMessageMap unacknowledgedMessageMap) throws AMQException; + + void messageFullyReceived(boolean persistent) throws AMQException; +} diff --git a/java/broker/main/org/apache/qpid/server/txn/TxnBuffer.java b/java/broker/main/org/apache/qpid/server/txn/TxnBuffer.java new file mode 100644 index 0000000000..4e141495c2 --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/txn/TxnBuffer.java @@ -0,0 +1,119 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +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."); + if (prepare()) + { + _log.debug("Transaction Succeeded"); + for (TxnOp op : _ops) + { + op.commit(); + } + } + else + { + _log.debug("Transaction Failed"); + } + } + 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/main/org/apache/qpid/server/txn/TxnOp.java b/java/broker/main/org/apache/qpid/server/txn/TxnOp.java new file mode 100644 index 0000000000..1a81786460 --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/txn/TxnOp.java @@ -0,0 +1,51 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +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() throws AMQException; + /** + * This is not the same as rollback. Unfortunately the use of an + * in memory reference count as a locking mechanism and a test for + * whether a message should be deleted means that as things are, + * handling an acknowledgement unavoidably alters both memory and + * persistent state on prepare. This is needed to 'compensate' or + * undo the in-memory change if the peristent update of later ops + * fails. + */ + public void undoPrepare(); + /** + * Rolls back the operation. + */ + public void rollback() throws AMQException; +} diff --git a/java/broker/main/org/apache/qpid/server/util/CircularBuffer.java b/java/broker/main/org/apache/qpid/server/util/CircularBuffer.java new file mode 100644 index 0000000000..d2c10cb4d1 --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/util/CircularBuffer.java @@ -0,0 +1,123 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +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/main/org/apache/qpid/server/util/LoggingProxy.java b/java/broker/main/org/apache/qpid/server/util/LoggingProxy.java new file mode 100644 index 0000000000..03c4896422 --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/util/LoggingProxy.java @@ -0,0 +1,102 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +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/main/org/apache/qpid/server/util/NullApplicationRegistry.java b/java/broker/main/org/apache/qpid/server/util/NullApplicationRegistry.java new file mode 100644 index 0000000000..0fab1f6895 --- /dev/null +++ b/java/broker/main/org/apache/qpid/server/util/NullApplicationRegistry.java @@ -0,0 +1,106 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +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/log4j.properties b/java/broker/src/log4j.properties deleted file mode 100644 index 3ff6f0b581..0000000000 --- a/java/broker/src/log4j.properties +++ /dev/null @@ -1,6 +0,0 @@ -log4j.rootCategory=${amqj.logging.level}, console - -log4j.appender.console=org.apache.log4j.ConsoleAppender -log4j.appender.console.Threshold=info -log4j.appender.console.layout=org.apache.log4j.PatternLayout -log4j.appender.console.layout.ConversionPattern=%t %d %p [%c{4}] %m%n 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 e3d9bc31ff..0000000000 --- a/java/broker/src/org/apache/qpid/server/AMQChannel.java +++ /dev/null @@ -1,565 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -package org.apache.qpid.server; - -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.BasicPublishBody; -import org.apache.qpid.framing.ContentBody; -import org.apache.qpid.framing.ContentHeaderBody; -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.MessageHandleFactory; -import org.apache.qpid.server.store.MessageStore; -import org.apache.qpid.server.txn.LocalTransactionalContext; -import org.apache.qpid.server.txn.TransactionalContext; -import org.apache.qpid.server.txn.TxnBuffer; -import org.apache.qpid.server.txn.NonTransactionalContext; - -import javax.management.MalformedObjectNameException; -import javax.management.ObjectName; -import java.util.*; -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 _prefetchCount; - - /** - * 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 Map _unacknowledgedMessageMap = new LinkedHashMap(DEFAULT_PREFETCH); - private UnacknowledgedMessageMap _unacknowledgedMessageMap = new UnacknowledgedMessageMapImpl(DEFAULT_PREFETCH); - - private final AtomicBoolean _suspended = new AtomicBoolean(false); - - private final MessageRouter _exchanges; - - private TransactionalContext _txnContext; - - private final List _returnMessages = new LinkedList(); - - private MessageHandleFactory _messageHandleFactory = new MessageHandleFactory(); - - public AMQChannel(int channelId, MessageStore messageStore, MessageRouter exchanges) - throws AMQException - { - _channelId = channelId; - _prefetchCount = DEFAULT_PREFETCH; - _messageStore = messageStore; - _exchanges = exchanges; - // TODO: fix me to pass in the txn context or at least have a factory for it - _txnContext = new NonTransactionalContext(_messageStore, this, _returnMessages); - } - - /** - * Sets this channel to be part of a local transaction - */ - public void setLocalTransactional() - { - _txnContext = new LocalTransactionalContext(_messageStore, new TxnBuffer(_messageStore), _returnMessages); - } - - public int getChannelId() - { - return _channelId; - } - - public long getPrefetchCount() - { - return _prefetchCount; - } - - public void setPrefetchCount(long prefetchCount) - { - _prefetchCount = prefetchCount; - } - - public void setPublishFrame(BasicPublishBody publishBody, AMQProtocolSession publisher) throws AMQException - { - _currentMessage = new AMQMessage(_messageStore.getNewMessageId(), publishBody, _txnContext); - // TODO: used in clustering only I think (RG) - //_currentMessage.setPublisher(publisher); - } - - public void publishContentHeader(ContentHeaderBody contentHeaderBody) - throws AMQException - { - if (_currentMessage == null) - { - throw new AMQException("Received content header without previously receiving a BasicPublish frame"); - } - else - { - _currentMessage.setContentHeaderBody(contentHeaderBody); - routeCurrentMessage(); - _currentMessage.routingComplete(_messageStore, _messageHandleFactory); - - // check and deliver if header says body length is zero - if (contentHeaderBody.bodySize == 0) - { - _currentMessage = null; - } - } - } - - public void publishContentBody(ContentBody contentBody) - throws AMQException - { - if (_currentMessage == null) - { - throw new AMQException("Received content body without previously receiving a JmsPublishBody"); - } - - // returns true iff the message was delivered (i.e. if all data was - // received - try - { - if (_currentMessage.addContentBodyFrame(contentBody)) - { - _currentMessage = null; - } - } - catch (AMQException e) - { - // we want to make sure we don't keep a reference to the message in the - // event of an error - _currentMessage = null; - throw e; - } - } - - protected void routeCurrentMessage() throws AMQException - { - _exchanges.routeContent(_currentMessage); - } - - /*protected void routeCurrentMessage2() 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); - } - else - { - throw new AMQException(_log, "Consumer tag " + consumerTag + " not known to channel " + - _channelId); - } - } - - /** - * 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 - } - } */ - _txnContext.rollback(); - 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 the message that was delivered - * @param deliveryTag the delivery tag used when delivering the message (see protocol spec for description of - * the delivery tag) - * @param queue the queue from which the message was delivered - */ - public void addUnacknowledgedMessage(AMQMessage message, long deliveryTag, String consumerTag, AMQQueue queue) - { - _unacknowledgedMessageMap.add(deliveryTag, new UnacknowledgedMessage(queue, message, consumerTag, 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. - * @throws org.apache.qpid.AMQException if the requeue fails - */ - 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 - Collection messagesToBeDelivered = _unacknowledgedMessageMap.cancelAllMessages(); - - for (UnacknowledgedMessage unacked : messagesToBeDelivered) - { - if (unacked.queue != null) - { - _txnContext.deliver(unacked.message, unacked.queue); - } - } - } - - /** - * Called to resend all outstanding unacknowledged messages to this same channel. - */ - public void resend(final AMQProtocolSession session) throws AMQException - { - _unacknowledgedMessageMap.visit(new UnacknowledgedMessageMap.Visitor() - { - public boolean callback(UnacknowledgedMessage message) throws AMQException - { - long deliveryTag = message.deliveryTag; - String consumerTag = message.consumerTag; - AMQMessage msg = message.message; - - msg.writeDeliver(session, _channelId, deliveryTag, consumerTag); - // false means continue processing - return false; - } - - public void visitComplete() - { - } - }); - } - - /** - * Callback indicating that a queue has been deleted. We must update the structure of unacknowledged - * messages to remove the queue reference and also decrement any message reference counts, without - * actually removing the item since we may get an ack for a delivery tag that was generated from the - * deleted queue. - * - * @param queue the queue that has been deleted - * @throws org.apache.qpid.AMQException if there is an error processing the unacked messages - */ - public void queueDeleted(final AMQQueue queue) throws AMQException - { - _unacknowledgedMessageMap.visit(new UnacknowledgedMessageMap.Visitor() - { - public boolean callback(UnacknowledgedMessage message) throws AMQException - { - if (message.queue == queue) - { - message.queue = null; - try - { - message.message.decrementReference(); - } - catch (AMQException e) - { - _log.error("Error decrementing ref count on message " + message.message.getMessageId() + ": " + - e, e); - } - } - return false; - } - - public void visitComplete() - { - } - }); - } - - /** - * 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 - { - _unacknowledgedMessageMap.acknowledgeMessage(deliveryTag, multiple, _txnContext); - checkSuspension(); - /*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); - } */ - } - - /** - * Used only for testing purposes. - * - * @return the map of unacknowledged messages - */ - public UnacknowledgedMessageMap getUnacknowledgedMessageMap() - { - return _unacknowledgedMessageMap; - } - - private void checkSuspension() - { - boolean suspend = _unacknowledgedMessageMap.size() >= _prefetchCount; - setSuspended(suspend); - } - - public void setSuspended(boolean suspended) - { - 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 - { - _txnContext.commit(); - } - - public void rollback() throws AMQException - { - _txnContext.rollback(); - } - - public String toString() - { - StringBuilder sb = new StringBuilder(30); - sb.append("Channel: id ").append(_channelId).append(", transaction context: ").append(_txnContext); - sb.append(", prefetch count: ").append(_prefetchCount); - return sb.toString(); - } - - public ObjectName getObjectName() - throws MalformedObjectNameException - { - StringBuilder sb = new StringBuilder(30); - sb.append("Channel:id=").append(_channelId); - return new ObjectName(sb.toString()); - } - - public void setDefaultQueue(AMQQueue queue) - { - _defaultQueue = queue; - } - - public AMQQueue getDefaultQueue() - { - return _defaultQueue; - } - - public void processReturns(AMQProtocolSession session) throws AMQException - { - for (RequiredDeliveryException bouncedMessage : _returnMessages) - { - AMQMessage message = bouncedMessage.getAMQMessage(); - message.writeReturn(session, _channelId, bouncedMessage.getReplyCode(), bouncedMessage.getMessage()); - } - _returnMessages.clear(); - } -} 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 6a7e54bc45..0000000000 --- a/java/broker/src/org/apache/qpid/server/ConsumerTagNotUniqueException.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -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 13dc5fbca6..0000000000 --- a/java/broker/src/org/apache/qpid/server/Main.java +++ /dev/null @@ -1,613 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -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.SocketAcceptorConfig; -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 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); - - 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(); - SocketAcceptorConfig sconfig = (SocketAcceptorConfig) acceptor.getDefaultConfig(); - SocketSessionConfig sc = (SocketSessionConfig) sconfig.getSessionConfig(); - - sc.setReceiveBufferSize(connectorConfig.socketReceiveBufferSize); - sc.setSendBufferSize(connectorConfig.socketWriteBuferSize); - sc.setTcpNoDelay(connectorConfig.tcpNoDelay); - - // if we do not use the executor pool threading model we get the default leader follower - // implementation provided by MINA - if (connectorConfig.enableExecutorPool) - { - sconfig.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.bind(bindAddress, handler, sconfig); - _logger.info("Qpid.AMQP listening on non-SSL address " + bindAddress); - } - - if (connectorConfig.enableSSL) - { - AMQPFastProtocolHandler handler = new AMQPProtocolProvider().getHandler(); - handler.setUseSSL(true); - try - { - acceptor.bind(new InetSocketAddress(connectorConfig.sslPort), - handler, sconfig); - _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 815dfdcfbd..0000000000 --- a/java/broker/src/org/apache/qpid/server/ManagedChannel.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -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 d2b017275a..0000000000 --- a/java/broker/src/org/apache/qpid/server/RequiredDeliveryException.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -package org.apache.qpid.server; - -import org.apache.qpid.AMQException; -import org.apache.qpid.server.queue.AMQMessage; - -/** - * Signals that a required delivery could not be made. This could be bacuse of - * the immediate flag being set and the queue having no consumers, or the mandatory - * flag being set and the exchange having no valid bindings. - */ -public abstract class RequiredDeliveryException extends AMQException -{ - private final AMQMessage _amqMessage; - - public RequiredDeliveryException(String message, AMQMessage payload) - { - super(message); - _amqMessage = payload; - } - - public AMQMessage getAMQMessage() - { - return _amqMessage; - } - - 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 85072b6976..0000000000 --- a/java/broker/src/org/apache/qpid/server/ack/TxAck.java +++ /dev/null @@ -1,125 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -package org.apache.qpid.server.ack; - -import org.apache.qpid.AMQException; -import org.apache.qpid.server.txn.TxnOp; - -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 f13ecef7ac..0000000000 --- a/java/broker/src/org/apache/qpid/server/ack/UnacknowledgedMessage.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -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 8fece7bcc1..0000000000 --- a/java/broker/src/org/apache/qpid/server/ack/UnacknowledgedMessageMap.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -package org.apache.qpid.server.ack; - -import org.apache.qpid.server.txn.TransactionalContext; -import org.apache.qpid.AMQException; - -import java.util.Collection; -import java.util.List; - -public interface UnacknowledgedMessageMap -{ - public interface Visitor - { - /** - * @param message the message being iterated over - * @return true to stop iteration, false to continue - * @throws AMQException - */ - boolean callback(UnacknowledgedMessage message) throws AMQException; - - void visitComplete(); - } - - void visit(Visitor visitor) throws AMQException; - - void add(long deliveryTag, UnacknowledgedMessage message); - - void collect(long deliveryTag, boolean multiple, List msgs); - - boolean contains(long deliveryTag) throws AMQException; - - void remove(List msgs); - - UnacknowledgedMessage remove(long deliveryTag); - - void drainTo(Collection destination, long deliveryTag) throws AMQException; - - Collection cancelAllMessages(); - - void acknowledgeMessage(long deliveryTag, boolean multiple, TransactionalContext txnContext) throws AMQException; - - int size(); - - void clear(); -} - 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 8061687175..0000000000 --- a/java/broker/src/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java +++ /dev/null @@ -1,211 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -package org.apache.qpid.server.ack; - -import org.apache.qpid.server.queue.AMQMessage; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.txn.TransactionalContext; -import org.apache.qpid.AMQException; - -import java.util.*; - -public class UnacknowledgedMessageMapImpl implements UnacknowledgedMessageMap -{ - private final Object _lock = new Object(); - - private Map _map; - - private long _lastDeliveryTag; - - private final int _prefetchLimit; - - public UnacknowledgedMessageMapImpl(int prefetchLimit) - { - _prefetchLimit = prefetchLimit; - _map = new LinkedHashMap(prefetchLimit); - } - - /*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 boolean contains(long deliveryTag) throws AMQException - { - synchronized (_lock) - { - return _map.containsKey(deliveryTag); - } - } - - public void remove(List msgs) - { - synchronized (_lock) - { - for(UnacknowledgedMessage msg : msgs) - { - _map.remove(msg.deliveryTag); - } - } - } - - public UnacknowledgedMessage remove(long deliveryTag) - { - synchronized (_lock) - { - return _map.remove(deliveryTag); - } - } - - public void visit(Visitor visitor) throws AMQException - { - synchronized (_lock) - { - Collection currentEntries = _map.values(); - for (UnacknowledgedMessage msg: currentEntries) - { - visitor.callback(msg); - } - } - } - - public void add(long deliveryTag, UnacknowledgedMessage message) - { - synchronized( _lock) - { - _map.put(deliveryTag, message); - _lastDeliveryTag = deliveryTag; - } - } - - public Collection cancelAllMessages() - { - synchronized (_lock) - { - Collection currentEntries = _map.values(); - _map = new LinkedHashMap(_prefetchLimit); - return currentEntries; - } - } - - public void acknowledgeMessage(long deliveryTag, boolean multiple, TransactionalContext txnContext) - throws AMQException - { - synchronized (_lock) - { - txnContext.acknowledgeMessage(deliveryTag, _lastDeliveryTag, multiple, this); - } - } - - public int size() - { - synchronized (_lock) - { - return _map.size(); - } - } - - public void clear() - { - synchronized (_lock) - { - _map.clear(); - } - } - - public void drainTo(Collection destination, long deliveryTag) throws AMQException - { - synchronized (_lock) - { - Iterator> it = _map.entrySet().iterator(); - while (it.hasNext()) - { - Map.Entry unacked = it.next(); - - if (unacked.getKey() > deliveryTag) - { - //This should not occur now. - throw new AMQException("UnacknowledgedMessageMap is out of order:" + unacked.getKey() + - " When deliveryTag is:" + deliveryTag + "ES:" + _map.entrySet().toString()); - } - - it.remove(); - - destination.add(unacked.getValue()); - if (unacked.getKey() == deliveryTag) - { - break; - } - } - } - } - - public void resendMessages(AMQProtocolSession protocolSession, int channelId) throws AMQException - { - synchronized (_lock) - { - for (Map.Entry entry : _map.entrySet()) - { - long deliveryTag = entry.getKey(); - String consumerTag = entry.getValue().consumerTag; - AMQMessage msg = entry.getValue().message; - - msg.writeDeliver(protocolSession, channelId, deliveryTag, consumerTag); - } - } - } - 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 e02b958941..0000000000 --- a/java/broker/src/org/apache/qpid/server/configuration/Configurator.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -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 a7ad50917c..0000000000 --- a/java/broker/src/org/apache/qpid/server/configuration/VirtualHostConfiguration.java +++ /dev/null @@ -1,217 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -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 cf787b4739..0000000000 --- a/java/broker/src/org/apache/qpid/server/exchange/AbstractExchange.java +++ /dev/null @@ -1,136 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -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 990a868e72..0000000000 --- a/java/broker/src/org/apache/qpid/server/exchange/DefaultExchangeFactory.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -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 62b0415253..0000000000 --- a/java/broker/src/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -package org.apache.qpid.server.exchange; - -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; -import org.apache.qpid.server.protocol.ExchangeInitialiser; -import org.apache.qpid.server.queue.AMQMessage; - -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 BasicPublish being received (where the exchange is validated) and the final - // content body being received (which triggers this method) - // TODO: check where the exchange is validated - 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 38ceebe235..0000000000 --- a/java/broker/src/org/apache/qpid/server/exchange/DestNameExchange.java +++ /dev/null @@ -1,219 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -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", - "Queue and binding keye", - _bindingItemNames, - _bindingItemDescriptions, - _bindingItemTypes); - _bindinglistDataType = new TabularType("Bindings", - "List of queues and binding keys", - _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 - { - final 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) - { - payload.enqueue(q); - } - } - } -} 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 6f38013ffb..0000000000 --- a/java/broker/src/org/apache/qpid/server/exchange/DestWildExchange.java +++ /dev/null @@ -1,223 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -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", - "Queue and binding keye", - _bindingItemNames, - _bindingItemDescriptions, - _bindingItemTypes); - _bindinglistDataType = new TabularType("Bindings", - "List of queues and binding keys", - _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 - payload.enqueue(q); - } - } - - 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 02a0badb65..0000000000 --- a/java/broker/src/org/apache/qpid/server/exchange/Exchange.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -package org.apache.qpid.server.exchange; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.server.queue.AMQMessage; -import org.apache.qpid.server.queue.AMQQueue; - -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 36fd159f31..0000000000 --- a/java/broker/src/org/apache/qpid/server/exchange/ExchangeFactory.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -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 4a6c735bee..0000000000 --- a/java/broker/src/org/apache/qpid/server/exchange/ExchangeInUseException.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -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 5b71cd7b0c..0000000000 --- a/java/broker/src/org/apache/qpid/server/exchange/ExchangeRegistry.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -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 d69e956b5f..0000000000 --- a/java/broker/src/org/apache/qpid/server/exchange/HeadersBinding.java +++ /dev/null @@ -1,142 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -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 67a6ff6596..0000000000 --- a/java/broker/src/org/apache/qpid/server/exchange/HeadersExchange.java +++ /dev/null @@ -1,239 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -package org.apache.qpid.server.exchange; - -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.*; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.queue.AMQMessage; -import org.apache.qpid.server.management.MBeanDescription; -import org.apache.qpid.server.management.MBeanConstructor; - -import javax.management.openmbean.*; -import javax.management.ServiceNotFoundException; -import javax.management.NotCompliantMBeanException; -import java.util.concurrent.CopyOnWriteArrayList; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.Map; - -/** - * 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 = {"Queue"}; - 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 and header attributes binding", - _bindingItemNames, - _bindingItemDescriptions, - _bindingItemTypes); - _bindinglistDataType = new TabularType("HeaderBindings", - "List of queues and related header attribute bindings", - _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; - } - - public void createBinding(String QueueName, String binding) - throws ServiceNotFoundException - { - throw new ServiceNotFoundException("This service is not supported by \"" + this.getName() + "\""); - } - - } // 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 routed = 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()); - } - payload.enqueue(e.queue); - routed = true; - } - } - if (!routed) - { - _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 9e88b6a68c..0000000000 --- a/java/broker/src/org/apache/qpid/server/exchange/Index.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -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 bd02910d0a..0000000000 --- a/java/broker/src/org/apache/qpid/server/exchange/ManagedExchange.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -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 832a60c681..0000000000 --- a/java/broker/src/org/apache/qpid/server/exchange/MessageRouter.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -package org.apache.qpid.server.exchange; - -import org.apache.qpid.AMQException; -import org.apache.qpid.server.queue.AMQMessage; - -/** - * 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 6d5511d9c8..0000000000 --- a/java/broker/src/org/apache/qpid/server/exchange/NoRouteException.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -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 5e236f7da9..0000000000 --- a/java/broker/src/org/apache/qpid/server/handler/BasicAckMethodHandler.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -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 52d6d9f0f1..0000000000 --- a/java/broker/src/org/apache/qpid/server/handler/BasicCancelMethodHandler.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -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 40d49815e3..0000000000 --- a/java/broker/src/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -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 f2f660299d..0000000000 --- a/java/broker/src/org/apache/qpid/server/handler/BasicPublishMethodHandler.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -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 0d1c039207..0000000000 --- a/java/broker/src/org/apache/qpid/server/handler/BasicQosHandler.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -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 1dce283c9e..0000000000 --- a/java/broker/src/org/apache/qpid/server/handler/BasicRecoverMethodHandler.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -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 1b03f15d22..0000000000 --- a/java/broker/src/org/apache/qpid/server/handler/ChannelCloseHandler.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -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 7731e56d4d..0000000000 --- a/java/broker/src/org/apache/qpid/server/handler/ChannelCloseOkHandler.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -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 1ad917b918..0000000000 --- a/java/broker/src/org/apache/qpid/server/handler/ChannelFlowHandler.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -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 634cd70469..0000000000 --- a/java/broker/src/org/apache/qpid/server/handler/ChannelOpenHandler.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -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 f78d6f7276..0000000000 --- a/java/broker/src/org/apache/qpid/server/handler/ConnectionCloseMethodHandler.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -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 f918158edb..0000000000 --- a/java/broker/src/org/apache/qpid/server/handler/ConnectionCloseOkMethodHandler.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -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 7bc28f9eb9..0000000000 --- a/java/broker/src/org/apache/qpid/server/handler/ConnectionOpenMethodHandler.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -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 1c0da4f658..0000000000 --- a/java/broker/src/org/apache/qpid/server/handler/ConnectionSecureOkMethodHandler.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -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 5715ce181b..0000000000 --- a/java/broker/src/org/apache/qpid/server/handler/ConnectionStartOkMethodHandler.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -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 05ca10fec5..0000000000 --- a/java/broker/src/org/apache/qpid/server/handler/ConnectionTuneOkMethodHandler.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -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 444a54a4f2..0000000000 --- a/java/broker/src/org/apache/qpid/server/handler/ExchangeDeclareHandler.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -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 441e991872..0000000000 --- a/java/broker/src/org/apache/qpid/server/handler/ExchangeDeleteHandler.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -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 a689366a2f..0000000000 --- a/java/broker/src/org/apache/qpid/server/handler/OnCurrentThreadExecutor.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -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 98eec37a4a..0000000000 --- a/java/broker/src/org/apache/qpid/server/handler/QueueBindHandler.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -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 d1eb387748..0000000000 --- a/java/broker/src/org/apache/qpid/server/handler/QueueDeclareHandler.java +++ /dev/null @@ -1,124 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -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 82c1d93065..0000000000 --- a/java/broker/src/org/apache/qpid/server/handler/QueueDeleteHandler.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -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 14399b08f0..0000000000 --- a/java/broker/src/org/apache/qpid/server/handler/TxCommitHandler.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -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 ff2d79fb95..0000000000 --- a/java/broker/src/org/apache/qpid/server/handler/TxRollbackHandler.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -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 cf665950ca..0000000000 --- a/java/broker/src/org/apache/qpid/server/handler/TxSelectHandler.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -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()).setLocalTransactional(); - 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 da82d2166e..0000000000 --- a/java/broker/src/org/apache/qpid/server/jms/JmsConsumer.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -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 a5733ed4ef..0000000000 --- a/java/broker/src/org/apache/qpid/server/management/AMQManagedObject.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -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 cd0d58acdb..0000000000 --- a/java/broker/src/org/apache/qpid/server/management/DefaultManagedObject.java +++ /dev/null @@ -1,168 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -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 0cd43cecac..0000000000 --- a/java/broker/src/org/apache/qpid/server/management/JMXManagedObjectRegistry.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -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 595c97dd76..0000000000 --- a/java/broker/src/org/apache/qpid/server/management/MBeanAttribute.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; -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -/** - * 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 2ce275d50d..0000000000 --- a/java/broker/src/org/apache/qpid/server/management/MBeanConstructor.java +++ /dev/null @@ -1,37 +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; -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -/** - * 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 ef6993036f..0000000000 --- a/java/broker/src/org/apache/qpid/server/management/MBeanDescription.java +++ /dev/null @@ -1,36 +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; -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -/** - * 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 dcf05fa6fe..0000000000 --- a/java/broker/src/org/apache/qpid/server/management/MBeanIntrospector.java +++ /dev/null @@ -1,385 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -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 30fdf81eee..0000000000 --- a/java/broker/src/org/apache/qpid/server/management/MBeanOperation.java +++ /dev/null @@ -1,40 +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; -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -/** - * 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 919ac767c7..0000000000 --- a/java/broker/src/org/apache/qpid/server/management/MBeanOperationParameter.java +++ /dev/null @@ -1,35 +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; -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -/** - * 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 e62e1c7f87..0000000000 --- a/java/broker/src/org/apache/qpid/server/management/Managable.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -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 a38931a0d8..0000000000 --- a/java/broker/src/org/apache/qpid/server/management/ManagedBroker.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -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 4007337173..0000000000 --- a/java/broker/src/org/apache/qpid/server/management/ManagedObject.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -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 7270ec83b4..0000000000 --- a/java/broker/src/org/apache/qpid/server/management/ManagedObjectRegistry.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -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 ec80009d17..0000000000 --- a/java/broker/src/org/apache/qpid/server/management/ManagementConfiguration.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -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 3bf2c8d9ca..0000000000 --- a/java/broker/src/org/apache/qpid/server/management/NoopManagedObjectRegistry.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -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 0c8d049951..0000000000 --- a/java/broker/src/org/apache/qpid/server/protocol/AMQMethodEvent.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -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 e8d973cd91..0000000000 --- a/java/broker/src/org/apache/qpid/server/protocol/AMQMethodListener.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -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 9ede6157f4..0000000000 --- a/java/broker/src/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java +++ /dev/null @@ -1,681 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -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.*; -import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.server.exchange.ExchangeRegistry; -import org.apache.qpid.server.management.*; -import org.apache.qpid.server.queue.QueueRegistry; -import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.state.AMQStateManager; - -import javax.management.*; -import javax.management.monitor.MonitorNotification; -import javax.management.openmbean.*; -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; - - /* 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", - "ChannelName", - "Transactional", - "DefaultQueue", - "UnacknowledgedMessageCount"}; - private String[] _channelAttributeDescriptions = { "Channel Identifier", - "Channel Name", - "is Channel Transactional?", - "Default Queue Name", - "Unacknowledged Message Count"}; - private OpenType[] _channelAttributeTypes = { SimpleType.INTEGER, - SimpleType.OBJECTNAME, - SimpleType.BOOLEAN, - SimpleType.STRING, - SimpleType.INTEGER}; - /** - * Channels in the list will be indexed according to channelId. - */ - private String[] _indexNames = { "ChannelId" }; - - /** - * represents the data type for channel data. - */ - private CompositeType _channelType = null; - /** - * Datatype for list of channelsType. - */ - private TabularType _channelsType = null; - - 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", - "a Channel", - _channelAtttibuteNames, - _channelAttributeDescriptions, - _channelAttributeTypes); - - _channelsType = new TabularType("channelsType", - "List of available channelsType", - _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"); - } - 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"); - } - 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(); - //ManagedChannel channel = (AMQChannelMBean)amqChannel.getManagedObject(); - ObjectName channelObjectName = null; - - try - { - channelObjectName = channel.getObjectName(); - } - catch (MalformedObjectNameException ex) - { - _logger.error("Unable to create object name: ", ex); - } - - Object[] itemValues = {channel.getChannelId(), - channelObjectName, - (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 - { - contentFrameReceived(frame); - } - } - } - - 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().writeDeliver(). - * - * @param frame the frame to writeDeliver - */ - 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 78fb76ae27..0000000000 --- a/java/broker/src/org/apache/qpid/server/protocol/AMQPFastProtocolHandler.java +++ /dev/null @@ -1,227 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -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)) - { - //writeDeliver 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 0088db08bb..0000000000 --- a/java/broker/src/org/apache/qpid/server/protocol/AMQPProtocolProvider.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -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 402ebc329d..0000000000 --- a/java/broker/src/org/apache/qpid/server/protocol/AMQProtocolSession.java +++ /dev/null @@ -1,122 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -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 08c31ed3ff..0000000000 --- a/java/broker/src/org/apache/qpid/server/protocol/ExchangeInitialiser.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -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 d7678185d4..0000000000 --- a/java/broker/src/org/apache/qpid/server/protocol/HeartbeatConfig.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -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 2a800f327d..0000000000 --- a/java/broker/src/org/apache/qpid/server/protocol/ManagedConnection.java +++ /dev/null @@ -1,138 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -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. - */ - @MBeanAttribute(name="MaximumNumberOfAllowedChannels", - description="The maximum number of channels that can be opened using this connection") - Long getMaximumNumberOfAllowedChannels(); - - /** - * Sets the maximum number of channels allowed to be created using - * this connection. - * @param value - */ - 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/protocol/ManagedSession.java b/java/broker/src/org/apache/qpid/server/protocol/ManagedSession.java deleted file mode 100644 index 2a1a0b62c2..0000000000 --- a/java/broker/src/org/apache/qpid/server/protocol/ManagedSession.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -package org.apache.qpid.server.protocol; - -import java.util.Date; - -public interface ManagedSession -{ - static final String TYPE = "Connection"; - - Date getLastIoTime(); - - String getRemoteAddress(); - - long getWrittenBytes(); - - long getReadBytes(); -} 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 afab90dcc4..0000000000 --- a/java/broker/src/org/apache/qpid/server/queue/AMQMessage.java +++ /dev/null @@ -1,520 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -package org.apache.qpid.server.queue; - -import org.apache.mina.common.ByteBuffer; -import org.apache.qpid.AMQException; -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.TransactionalContext; -import org.apache.log4j.Logger; - -import java.util.*; -import java.util.concurrent.atomic.AtomicInteger; - -/** - * Combines the information that make up a deliverable message into a more manageable form. - */ -public class AMQMessage -{ - private static final Logger _log = Logger.getLogger(AMQMessage.class); - - /** - * Used in clustering - */ - private final Set _tokens = new HashSet(); - - /** - * Used in clustering - * TODO need to get rid of this - */ - private AMQProtocolSession _publisher; - - private final long _messageId; - - private final AtomicInteger _referenceCount = new AtomicInteger(1); - - private AMQMessageHandle _messageHandle; - - /** - * Stored temporarily until the header has been received at which point it is used when - * constructing the handle - */ - private BasicPublishBody _publishBody; - - /** - * Also stored temporarily. - */ - private ContentHeaderBody _contentHeaderBody; - - /** - * Keeps a track of how many bytes we have received in body frames - */ - private long _bodyLengthReceived = 0; - - private final TransactionalContext _txnContext; - - /** - * 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; - - /** - * This is stored during routing, to know the queues to which this message should immediately be - * delivered. It is cleared after delivery has been attempted. Any persistent record of destinations is done - * by the message handle. - */ - private List _destinationQueues = new LinkedList(); - - /** - * Used to iterate through all the body frames associated with this message. Will not - * keep all the data in memory therefore is memory-efficient. - */ - private class BodyFrameIterator implements Iterator - { - private int _channel; - - private int _index = -1; - - private BodyFrameIterator(int channel) - { - _channel = channel; - } - - public boolean hasNext() - { - return _index < _messageHandle.getBodyCount() - 1; - } - - public AMQDataBlock next() - { - try - { - ContentBody cb = _messageHandle.getContentBody(_messageId, ++_index); - return ContentBody.createAMQFrame(_channel, cb); - } - catch (AMQException e) - { - // have no choice but to throw a runtime exception - throw new RuntimeException("Error getting content body: " + e, e); - } - - } - - public void remove() - { - throw new UnsupportedOperationException(); - } - } - - private class BodyContentIterator implements Iterator - { - - private int _index = -1; - - public boolean hasNext() - { - return _index < _messageHandle.getBodyCount() - 1; - } - - public ContentBody next() - { - try - { - return _messageHandle.getContentBody(_messageId, ++_index); - } - catch (AMQException e) - { - throw new RuntimeException("Error getting content body: " + e, e); - } - } - - public void remove() - { - throw new UnsupportedOperationException(); - } - } - - public AMQMessage(long messageId, BasicPublishBody publishBody, TransactionalContext txnContext) - { - _messageId = messageId; - _txnContext = txnContext; - _publishBody = publishBody; - if (_log.isDebugEnabled()) - { - _log.debug("Message created with id " + messageId); - } - } - - protected AMQMessage(AMQMessage msg) throws AMQException - { - _publisher = msg._publisher; - _messageId = msg._messageId; - _messageHandle = msg._messageHandle; - _txnContext = msg._txnContext; - _deliveredToConsumer = msg._deliveredToConsumer; - } - - public Iterator getBodyFrameIterator(int channel) - { - return new BodyFrameIterator(channel); - } - - public Iterator getContentBodyIterator() - { - return new BodyContentIterator(); - } - - public ContentHeaderBody getContentHeaderBody() throws AMQException - { - return _messageHandle.getContentHeaderBody(_messageId); - } - - public void setContentHeaderBody(ContentHeaderBody contentHeaderBody) - throws AMQException - { - _contentHeaderBody = contentHeaderBody; - } - - public void routingComplete(MessageStore store, MessageHandleFactory factory) throws AMQException - { - final boolean persistent = isPersistent(); - _messageHandle = factory.createMessageHandle(_messageId, store, persistent); - if (persistent) - { - _txnContext.beginTranIfNecessary(); - } - - // enqueuing the messages ensure that if required the destinations are recorded to a - // persistent store - for (AMQQueue q : _destinationQueues) - { - _messageHandle.enqueue(_messageId, q); - } - - if (_contentHeaderBody.bodySize == 0) - { - deliver(); - } - } - - public boolean addContentBodyFrame(ContentBody contentBody) throws AMQException - { - _bodyLengthReceived += contentBody.getSize(); - _messageHandle.addContentBodyFrame(_messageId, contentBody); - if (isAllContentReceived()) - { - deliver(); - return true; - } - else - { - return false; - } - } - - public boolean isAllContentReceived() throws AMQException - { - return _bodyLengthReceived == _contentHeaderBody.bodySize; - } - - public long getMessageId() - { - return _messageId; - } - - /** - * Threadsafe. Increment the reference count on the message. - */ - public void incrementReference() - { - _referenceCount.incrementAndGet(); - if (_log.isDebugEnabled()) - { - _log.debug("Ref count on message " + _messageId + " incremented to " + _referenceCount); - } - } - - /** - * Threadsafe. This will decrement the reference count and when it reaches zero will remove the message from the - * message store. - * - * @throws MessageCleanupException when an attempt was made to remove the message from the message store and that - * failed - */ - 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 - { - if (_log.isDebugEnabled()) - { - _log.debug("Ref count on message " + _messageId + " is zero; removing message"); - } - _messageHandle.removeMessage(_messageId); - } - catch (AMQException e) - { - //to maintain consistency, we revert the count - incrementReference(); - throw new MessageCleanupException(_messageId, e); - } - } - else - { - if (_log.isDebugEnabled()) - { - _log.debug("Ref count is now " + _referenceCount + " for message id " + _messageId); - if (_referenceCount.get() < 0) - { - Thread.dumpStack(); - } - } - } - } - - 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; - } - } - - /** - * Registers a queue to which this message is to be delivered. This is - * called from the exchange when it is routing the message. This will be called before any content bodies have - * been received so that the choice of AMQMessageHandle implementation can be picked based on various criteria. - * - * @param queue the queue - * @throws org.apache.qpid.AMQException if there is an error enqueuing the message - */ - public void enqueue(AMQQueue queue) throws AMQException - { - _destinationQueues.add(queue); - } - - public void dequeue(AMQQueue queue) throws AMQException - { - _messageHandle.dequeue(_messageId, queue); - } - - public boolean isPersistent() throws AMQException - { - if (_contentHeaderBody != null) - { - //todo remove literal values to a constant file such as AMQConstants in common - return _contentHeaderBody.properties instanceof BasicContentHeaderProperties && - ((BasicContentHeaderProperties) _contentHeaderBody.properties).getDeliveryMode() == 2; - } - else - { - return _messageHandle.isPersistent(_messageId); - } - } - - /** - * 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, AMQException - { - BasicPublishBody pb = getPublishBody(); - if (pb.immediate && !_deliveredToConsumer) - { - throw new NoConsumersException(this); - } - } - - public BasicPublishBody getPublishBody() throws AMQException - { - BasicPublishBody pb; - if (_publishBody != null) - { - pb = _publishBody; - } - else - { - pb = _messageHandle.getPublishBody(_messageId); - } - return pb; - } - - /** - * Called when this message is delivered to a consumer. (used to - * implement the 'immediate' flag functionality). - */ - public void setDeliveredToConsumer() - { - _deliveredToConsumer = true; - } - - /*public void registerQueue(AMQQueue queue) - { - _destinationQueues.add(queue); - } */ - - private void deliver() throws AMQException - { - // first we allow the handle to know that the message has been fully received. This is useful if it is - // maintaining any calculated values based on content chunks - try - { - _messageHandle.setPublishAndContentHeaderBody(_messageId, _publishBody, _contentHeaderBody); - _publishBody = null; - _contentHeaderBody = null; - - // we then allow the transactional context to do something with the message content - // now that it has all been received, before we attempt delivery - _txnContext.messageFullyReceived(isPersistent()); - for (AMQQueue q : _destinationQueues) - { - _txnContext.deliver(this, q); - } - } - finally - { - _destinationQueues.clear(); - _destinationQueues = null; - decrementReference(); - } - } - - public void writeDeliver(AMQProtocolSession protocolSession, int channelId, long deliveryTag, String consumerTag) - throws AMQException - { - ByteBuffer deliver = createEncodedDeliverFrame(channelId, deliveryTag, consumerTag); - AMQDataBlock contentHeader = ContentHeaderBody.createAMQFrame(channelId, - getContentHeaderBody()); - - Iterator bodyFrameIterator = getBodyFrameIterator(channelId); - // - // Optimise the case where we have a single content body. In that case we create a composite block - // so that we can writeDeliver out the deliver, header and body with a single network writeDeliver. - // - if (bodyFrameIterator.hasNext()) - { - AMQDataBlock firstContentBody = bodyFrameIterator.next(); - AMQDataBlock[] headerAndFirstContent = new AMQDataBlock[]{contentHeader, firstContentBody}; - CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(deliver, headerAndFirstContent); - protocolSession.writeFrame(compositeBlock); - } - else - { - CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(deliver, - new AMQDataBlock[]{contentHeader}); - protocolSession.writeFrame(compositeBlock); - } - - // - // Now start writing out the other content bodies - // TODO: MINA needs to be fixed so the the pending writes buffer is not unbounded - // - while (bodyFrameIterator.hasNext()) - { - protocolSession.writeFrame(bodyFrameIterator.next()); - } - - } - - private ByteBuffer createEncodedDeliverFrame(int channelId, long deliveryTag, String consumerTag) - throws AMQException - { - BasicPublishBody pb = getPublishBody(); - AMQFrame deliverFrame = BasicDeliverBody.createAMQFrame(channelId, consumerTag, - deliveryTag, false, pb.exchange, - pb.routingKey); - ByteBuffer buf = ByteBuffer.allocate((int) deliverFrame.getSize()); // XXX: Could cast be a problem? - deliverFrame.writePayload(buf); - buf.flip(); - return buf; - } - - private ByteBuffer createEncodedReturnFrame(int channelId, int replyCode, String replyText) - { - AMQFrame returnFrame = BasicReturnBody.createAMQFrame(channelId, replyCode, replyText, _publishBody.exchange, - _publishBody.routingKey); - ByteBuffer buf = ByteBuffer.allocate((int) returnFrame.getSize()); // XXX: Could cast be a problem? - returnFrame.writePayload(buf); - buf.flip(); - return buf; - } - - public void writeReturn(AMQProtocolSession protocolSession, int channelId, int replyCode, String replyText) - throws AMQException - { - ByteBuffer returnFrame = createEncodedReturnFrame(channelId, replyCode, replyText); - - AMQDataBlock contentHeader = ContentHeaderBody.createAMQFrame(channelId, - getContentHeaderBody()); - - Iterator bodyFrameIterator = getBodyFrameIterator(channelId); - // - // Optimise the case where we have a single content body. In that case we create a composite block - // so that we can writeDeliver out the deliver, header and body with a single network writeDeliver. - // - if (bodyFrameIterator.hasNext()) - { - AMQDataBlock firstContentBody = bodyFrameIterator.next(); - AMQDataBlock[] headerAndFirstContent = new AMQDataBlock[]{contentHeader, firstContentBody}; - CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(returnFrame, headerAndFirstContent); - protocolSession.writeFrame(compositeBlock); - } - else - { - CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(returnFrame, - new AMQDataBlock[]{contentHeader}); - protocolSession.writeFrame(compositeBlock); - } - - // - // Now start writing out the other content bodies - // TODO: MINA needs to be fixed so the the pending writes buffer is not unbounded - // - while (bodyFrameIterator.hasNext()) - { - protocolSession.writeFrame(bodyFrameIterator.next()); - } - } -} diff --git a/java/broker/src/org/apache/qpid/server/queue/AMQMessageHandle.java b/java/broker/src/org/apache/qpid/server/queue/AMQMessageHandle.java deleted file mode 100644 index 0fc9ec5dcd..0000000000 --- a/java/broker/src/org/apache/qpid/server/queue/AMQMessageHandle.java +++ /dev/null @@ -1,62 +0,0 @@ -/** - * User: Robert Greig - * Date: 23-Oct-2006 - ****************************************************************************** - * (c) Copyright JP Morgan Chase Ltd 2006. All rights reserved. No part of - * this program may be photocopied reproduced or translated to another - * program language without prior written consent of JP Morgan Chase Ltd - ******************************************************************************/ -package org.apache.qpid.server.queue; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.BasicPublishBody; -import org.apache.qpid.framing.ContentBody; -import org.apache.qpid.framing.ContentHeaderBody; - -/** - * A pluggable way of getting message data. Implementations can provide intelligent caching for example or - * even no caching at all to minimise the broker memory footprint. - * - * The method all take a messageId to avoid having to store it in the instance - the AMQMessage container - * must already keen the messageId so it is pointless storing it twice. - */ -public interface AMQMessageHandle -{ - ContentHeaderBody getContentHeaderBody(long messageId) throws AMQException; - - /** - * @return the number of body frames associated with this message - */ - int getBodyCount(); - - /** - * @return the size of the body - */ - long getBodySize(long messageId) throws AMQException; - - /** - * Get a particular content body - * @param index the index of the body to retrieve, must be between 0 and getBodyCount() - 1 - * @return a content body - * @throws IllegalArgumentException if the index is invalid - */ - ContentBody getContentBody(long messageId, int index) throws IllegalArgumentException, AMQException; - - void addContentBodyFrame(long messageId, ContentBody contentBody) throws AMQException; - - BasicPublishBody getPublishBody(long messageId) throws AMQException; - - boolean isRedelivered(); - - boolean isPersistent(long messageId) throws AMQException; - - void setPublishAndContentHeaderBody(long messageId, BasicPublishBody publishBody, - ContentHeaderBody contentHeaderBody) - throws AMQException; - - void removeMessage(long messageId) throws AMQException; - - void enqueue(long messageId, AMQQueue queue) throws AMQException; - - void dequeue(long messageId, AMQQueue queue) throws AMQException; -} \ No newline at end of file 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 d8bab6e3bc..0000000000 --- a/java/broker/src/org/apache/qpid/server/queue/AMQQueue.java +++ /dev/null @@ -1,764 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -package org.apache.qpid.server.queue; - -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.ContentBody; -import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.server.management.*; -import org.apache.qpid.server.protocol.AMQProtocolSession; - -import javax.management.*; -import javax.management.monitor.MonitorNotification; -import javax.management.openmbean.*; -import java.text.MessageFormat; -import java.util.ArrayList; -import java.util.Iterator; -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; - //private MBeanInfo _mbeanInfo; - - // AMQ message attribute names exposed. - private String[] _msgAttributeNames = { "MessageId", - "Redelivered", - "Content's size", - "Contents" }; - // AMQ Message attribute descriptions. - private String[] _msgAttributeDescriptions = { "Message Id", - "Redelivered", - "Message content's size in bytes", - "Message content bodies" }; - // AMQ message attribute types. - private OpenType[] _msgAttributeTypes = new OpenType[4]; - // Messages will be indexed according to the messageId. - private String[] _msgAttributeIndex = { "MessageId"}; - // Composite type for representing AMQ Message data. - private CompositeType _messageDataType = null; - // Datatype for representing AMQ messages list. - private TabularType _messagelistDataType = null; - - private String[] _contentNames = {"SerialNumber", "ContentBody"}; - private String[] _contentDesc = {"SerialNumber", "Message Content"}; - private String[] _contentIndex = {"SerialNumber"}; - private OpenType[] _contentType = new OpenType[2]; - private CompositeType _contentBodyType = null; - private TabularType _contentBodyListType = null; - - @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 - { - _contentType[0] = SimpleType.INTEGER; - _contentType[1] = new ArrayType(1, SimpleType.BYTE); - _contentBodyType = new CompositeType("Content", - "Message body content", - _contentNames, - _contentDesc, - _contentType); - _contentBodyListType = new TabularType("MessageContents", - "MessageContent", - _contentBodyType, - _contentIndex); - - _msgAttributeTypes[0] = SimpleType.LONG; - _msgAttributeTypes[1] = SimpleType.BOOLEAN; - _msgAttributeTypes[2] = SimpleType.LONG; - _msgAttributeTypes[3] = _contentBodyListType; - - _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() throws AMQException - { - List list = _deliveryMgr.getMessages(); - if (list.size() == 0) - return 0l; - - long queueSize = 0; - for (AMQMessage message : list) - { - queueSize = queueSize + getMessageSize(message); - } - return (long) Math.round(queueSize/100); - } - // Operations - - // calculates the size of an AMQMessage - private long getMessageSize(AMQMessage msg) throws AMQException - { - if (msg == null) - { - return 0L; - } - - return msg.getContentHeaderBody().bodySize; - } - - // Checks if there is any notification to be send to the listeners - private void checkForNotification(AMQMessage msg) throws AMQException - { - // 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()); - } - } - - /** - * 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(); - - if (beginIndex > list.size()) - { - throw new JMException("FromIndex = " + beginIndex + ". There are only " + list.size() + - " messages in the queue"); - } - - endIndex = endIndex < list.size() ? endIndex : list.size(); - TabularDataSupport _messageList = new TabularDataSupport(_messagelistDataType); - - for (int i = beginIndex; i <= endIndex; i++) - { - AMQMessage msg = list.get(i - 1); - long msgId = msg.getMessageId(); - - Iterator cBodies = msg.getContentBodyIterator(); - - TabularDataSupport _contentList = new TabularDataSupport(_contentBodyListType); - int contentSerialNo = 1; - long size = 0; - - while (cBodies.hasNext()) - { - ContentBody body = cBodies.next(); - if (body.getSize() != 0) - { - Byte[] byteArray = getByteArray(body.payload.slice().array()); - size = size + byteArray.length; - - Object[] contentValues = {contentSerialNo, byteArray}; - CompositeData contentData = new CompositeDataSupport(_contentBodyType, - _contentNames, - contentValues); - - _contentList.put(contentData); - } - } - - Object[] itemValues = {msgId, true, size, _contentList}; - CompositeData messageData = new CompositeDataSupport(_messageDataType, - _msgAttributeNames, - itemValues); - _messageList.put(messageData); - } - - return _messageList; - } - - /** - * A utility to convert byte[] to Byte[]. Required to create composite - * type for message contents. - * @param byteArray message content as byte[] - * @return Byte[] - */ - private Byte[] getByteArray(byte[] byteArray) - { - int size = byteArray.length; - List list = new ArrayList(); - - for (int i = 0; i < size; i++) - { - list.add(byteArray[i]); - } - - return list.toArray(new Byte[0]); - } - - /** - * 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; - _deliveryMgr = new DeliveryManager(_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.getQueueMessageCount() > 0) - { - _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(); - } */ - - public void process(AMQMessage msg) throws FailedDequeueException, AMQException - { - _deliveryMgr.deliver(getName(), msg); - updateReceivedMessageCount(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) throws AMQException - { - _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)); - } - } -} 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 60788c1ccb..0000000000 --- a/java/broker/src/org/apache/qpid/server/queue/AsyncDeliveryConfig.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -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/DefaultQueueRegistry.java b/java/broker/src/org/apache/qpid/server/queue/DefaultQueueRegistry.java deleted file mode 100644 index a7dc98ec22..0000000000 --- a/java/broker/src/org/apache/qpid/server/queue/DefaultQueueRegistry.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -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 55ecf799f6..0000000000 --- a/java/broker/src/org/apache/qpid/server/queue/DeliveryManager.java +++ /dev/null @@ -1,259 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -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 DeliveryManager -{ - private static final Logger _log = Logger.getLogger(DeliveryManager.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 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; - - DeliveryManager(SubscriptionManager subscriptions, AMQQueue queue) - { - _subscriptions = subscriptions; - _queue = queue; - } - - private synchronized boolean enqueue(AMQMessage msg) throws AMQException - { - if (_queueing) - { - if(msg.getPublishBody().immediate) - { - //can't enqueue messages for whom immediate delivery is required - return false; - } - else - { - _messages.offer(msg); - return true; - } - } - else - { - return false; - } - } - - private synchronized void startQueueing(AMQMessage msg) throws AMQException - { - _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 - */ - private synchronized boolean hasQueuedMessages() - { - boolean empty = _messages.isEmpty(); - if (empty) - { - _queueing = false; - } - return !empty; - } - - public synchronized int getQueueMessageCount() - { - return _messages.size(); - } - - protected synchronized List getMessages() - { - return new ArrayList(_messages); - } - - protected synchronized void removeAMessageFromTop() throws AMQException - { - AMQMessage msg = poll(); - if (msg != null) - { - msg.dequeue(_queue); - } - } - - protected 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(). - * @throws org.apache.qpid.AMQException if we cannot process the messages on the queue - */ - private void processQueue() throws AMQException - { - 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) - { - next.send(poll(), _queue); - } - else - { - hasSubscribers = false; - } - } - } - catch (FailedDequeueException e) - { - _log.error("Unable to deliver message as dequeue failed: " + e, e); - } - 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 - */ - 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 - * @throws FailedDequeueException if the message could not be dequeued - */ - void deliver(String name, AMQMessage msg) throws FailedDequeueException, AMQException - { - // first check whether we are queueing, and enqueue if we are - if (!enqueue(msg)) - { - // not queueing so deliver message to 'next' subscriber - Subscription s = _subscriptions.nextSubscriber(msg); - if (s == null) - { - if (!msg.getPublishBody().immediate) - { - // 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() - { - try - { - processQueue(); - } - catch (AMQException e) - { - _log.error("Error processing queue: " + e, e); - } - } - } -} 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 424330bd11..0000000000 --- a/java/broker/src/org/apache/qpid/server/queue/ExchangeBindings.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -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 f27d935c25..0000000000 --- a/java/broker/src/org/apache/qpid/server/queue/FailedDequeueException.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -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/InMemoryMessageHandle.java b/java/broker/src/org/apache/qpid/server/queue/InMemoryMessageHandle.java deleted file mode 100644 index e2e334c5f4..0000000000 --- a/java/broker/src/org/apache/qpid/server/queue/InMemoryMessageHandle.java +++ /dev/null @@ -1,110 +0,0 @@ -/** - * User: Robert Greig - * Date: 21-Nov-2006 - ****************************************************************************** - * (c) Copyright JP Morgan Chase Ltd 2006. All rights reserved. No part of - * this program may be photocopied reproduced or translated to another - * program language without prior written consent of JP Morgan Chase Ltd - ******************************************************************************/ -package org.apache.qpid.server.queue; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.BasicContentHeaderProperties; -import org.apache.qpid.framing.BasicPublishBody; -import org.apache.qpid.framing.ContentBody; -import org.apache.qpid.framing.ContentHeaderBody; - -import java.util.LinkedList; -import java.util.List; - -/** - */ -public class InMemoryMessageHandle implements AMQMessageHandle -{ - - private ContentHeaderBody _contentHeaderBody; - - private BasicPublishBody _publishBody; - - private List _contentBodies = new LinkedList(); - - private boolean _redelivered; - - public InMemoryMessageHandle() - { - } - - public ContentHeaderBody getContentHeaderBody(long messageId) throws AMQException - { - return _contentHeaderBody; - } - - public int getBodyCount() - { - return _contentBodies.size(); - } - - public long getBodySize(long messageId) throws AMQException - { - return getContentHeaderBody(messageId).bodySize; - } - - public ContentBody getContentBody(long messageId, int index) throws AMQException, IllegalArgumentException - { - if (index > _contentBodies.size() - 1) - { - throw new IllegalArgumentException("Index " + index + " out of valid range 0 to " + - (_contentBodies.size() - 1)); - } - return _contentBodies.get(index); - } - - public void addContentBodyFrame(long messageId, ContentBody contentBody) throws AMQException - { - _contentBodies.add(contentBody); - } - - public BasicPublishBody getPublishBody(long messageId) throws AMQException - { - return _publishBody; - } - - public boolean isRedelivered() - { - return _redelivered; - } - - public boolean isPersistent(long messageId) throws AMQException - { - //todo remove literal values to a constant file such as AMQConstants in common - ContentHeaderBody chb = getContentHeaderBody(messageId); - return chb.properties instanceof BasicContentHeaderProperties && - ((BasicContentHeaderProperties) chb.properties).getDeliveryMode() == 2; - } - - /** - * This is called when all the content has been received. - * @param publishBody - * @param contentHeaderBody - * @throws AMQException - */ - public void setPublishAndContentHeaderBody(long messageId, BasicPublishBody publishBody, - ContentHeaderBody contentHeaderBody) - throws AMQException - { - _publishBody = publishBody; - _contentHeaderBody = contentHeaderBody; - } - - public void removeMessage(long messageId) throws AMQException - { - } - - public void enqueue(long messageId, AMQQueue queue) throws AMQException - { - } - - public void dequeue(long messageId, AMQQueue queue) throws AMQException - { - } -} 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 7528011bac..0000000000 --- a/java/broker/src/org/apache/qpid/server/queue/ManagedQueue.java +++ /dev/null @@ -1,213 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -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 org.apache.qpid.AMQException; - -import javax.management.JMException; -import javax.management.MBeanOperationInfo; -import javax.management.openmbean.TabularData; -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, AMQException; - - /** - * 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; - -} 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 6f0fa285b1..0000000000 --- a/java/broker/src/org/apache/qpid/server/queue/MessageCleanupException.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -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/MessageHandleFactory.java b/java/broker/src/org/apache/qpid/server/queue/MessageHandleFactory.java deleted file mode 100644 index 93aceb76ec..0000000000 --- a/java/broker/src/org/apache/qpid/server/queue/MessageHandleFactory.java +++ /dev/null @@ -1,34 +0,0 @@ -/** - * User: Robert Greig - * Date: 31-Oct-2006 - ****************************************************************************** - * (c) Copyright JP Morgan Chase Ltd 2006. All rights reserved. No part of - * this program may be photocopied reproduced or translated to another - * program language without prior written consent of JP Morgan Chase Ltd - ******************************************************************************/ -package org.apache.qpid.server.queue; - -import org.apache.qpid.server.store.MessageStore; - -/** - * Constructs a message handle based on the publish body, the content header and the queue to which the message - * has been routed. - * - * @author Robert Greig (robert.j.greig@jpmorgan.com) - */ -public class MessageHandleFactory -{ - - public AMQMessageHandle createMessageHandle(long messageId, MessageStore store, boolean persistent) - { - // just hardcoded for now - if (persistent) - { - return new WeakReferenceMessageHandle(store); - } - else - { - return new InMemoryMessageHandle(); - } - } -} diff --git a/java/broker/src/org/apache/qpid/server/queue/MessageMetaData.java b/java/broker/src/org/apache/qpid/server/queue/MessageMetaData.java deleted file mode 100644 index deed18c188..0000000000 --- a/java/broker/src/org/apache/qpid/server/queue/MessageMetaData.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.qpid.server.queue; - -import org.apache.qpid.framing.BasicPublishBody; -import org.apache.qpid.framing.ContentHeaderBody; - -/** - * Encapsulates a publish body and a content header. In the context of the message store these are treated as a - * single unit. - */ -public class MessageMetaData -{ - private BasicPublishBody _publishBody; - - private ContentHeaderBody _contentHeaderBody; - - private int _contentChunkCount; - - public MessageMetaData(BasicPublishBody publishBody, ContentHeaderBody contentHeaderBody, int contentChunkCount) - { - _contentHeaderBody = contentHeaderBody; - _publishBody = publishBody; - _contentChunkCount = contentChunkCount; - } - - public int getContentChunkCount() - { - return _contentChunkCount; - } - - public void setContentChunkCount(int contentChunkCount) - { - _contentChunkCount = contentChunkCount; - } - - public ContentHeaderBody getContentHeaderBody() - { - return _contentHeaderBody; - } - - public void setContentHeaderBody(ContentHeaderBody contentHeaderBody) - { - _contentHeaderBody = contentHeaderBody; - } - - public BasicPublishBody getPublishBody() - { - return _publishBody; - } - - public void setPublishBody(BasicPublishBody publishBody) - { - _publishBody = publishBody; - } -} 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 09f01d6d97..0000000000 --- a/java/broker/src/org/apache/qpid/server/queue/NoConsumersException.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -package org.apache.qpid.server.queue; - -import org.apache.qpid.protocol.AMQConstant; -import org.apache.qpid.server.RequiredDeliveryException; - -/** - * 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(AMQMessage message) - { - super("Immediate delivery is not possible.", message); - } - - 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 bc5599fb20..0000000000 --- a/java/broker/src/org/apache/qpid/server/queue/QueueRegistry.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -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 a248efecb1..0000000000 --- a/java/broker/src/org/apache/qpid/server/queue/Subscription.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -package org.apache.qpid.server.queue; - -import org.apache.qpid.AMQException; - -public interface Subscription -{ - void send(AMQMessage msg, AMQQueue queue) throws AMQException; - - boolean isSuspended(); - - void queueDeleted(AMQQueue queue) throws AMQException; -} 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 127b19b0e4..0000000000 --- a/java/broker/src/org/apache/qpid/server/queue/SubscriptionFactory.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -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 4422d1ffc2..0000000000 --- a/java/broker/src/org/apache/qpid/server/queue/SubscriptionImpl.java +++ /dev/null @@ -1,170 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -package org.apache.qpid.server.queue; - -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; -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 AMQException - { - 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); - } - - msg.writeDeliver(protocolSession, channel.getChannelId(), deliveryTag, consumerTag); - } - } - 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) throws AMQException - { - channel.queueDeleted(queue); - } -} 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 185b0e4268..0000000000 --- a/java/broker/src/org/apache/qpid/server/queue/SubscriptionManager.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -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 fe55bd071b..0000000000 --- a/java/broker/src/org/apache/qpid/server/queue/SubscriptionSet.java +++ /dev/null @@ -1,182 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -package org.apache.qpid.server.queue; - -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; - -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) throws AMQException - { - for (Subscription s : _subscriptions) - { - s.queueDeleted(queue); - } - } - - int size() { - return _subscriptions.size(); - } -} diff --git a/java/broker/src/org/apache/qpid/server/queue/WeakReferenceMessageHandle.java b/java/broker/src/org/apache/qpid/server/queue/WeakReferenceMessageHandle.java deleted file mode 100644 index bf82940ec8..0000000000 --- a/java/broker/src/org/apache/qpid/server/queue/WeakReferenceMessageHandle.java +++ /dev/null @@ -1,144 +0,0 @@ -/** - * User: Robert Greig - * Date: 23-Oct-2006 - ****************************************************************************** - * (c) Copyright JP Morgan Chase Ltd 2006. All rights reserved. No part of - * this program may be photocopied reproduced or translated to another - * program language without prior written consent of JP Morgan Chase Ltd - ******************************************************************************/ -package org.apache.qpid.server.queue; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.BasicContentHeaderProperties; -import org.apache.qpid.framing.BasicPublishBody; -import org.apache.qpid.framing.ContentBody; -import org.apache.qpid.framing.ContentHeaderBody; -import org.apache.qpid.server.store.MessageStore; - -import java.lang.ref.WeakReference; -import java.util.LinkedList; -import java.util.List; - -/** - * @author Robert Greig (robert.j.greig@jpmorgan.com) - */ -public class WeakReferenceMessageHandle implements AMQMessageHandle -{ - private WeakReference _contentHeaderBody; - - private WeakReference _publishBody; - - private List> _contentBodies = new LinkedList>(); - - private boolean _redelivered; - - private final MessageStore _messageStore; - - public WeakReferenceMessageHandle(MessageStore messageStore) - { - _messageStore = messageStore; - } - - public ContentHeaderBody getContentHeaderBody(long messageId) throws AMQException - { - ContentHeaderBody chb = _contentHeaderBody.get(); - if (chb == null) - { - MessageMetaData mmd = _messageStore.getMessageMetaData(messageId); - chb = mmd.getContentHeaderBody(); - _contentHeaderBody = new WeakReference(chb); - _publishBody = new WeakReference(mmd.getPublishBody()); - } - return chb; - } - - public int getBodyCount() - { - return _contentBodies.size(); - } - - public long getBodySize(long messageId) throws AMQException - { - return getContentHeaderBody(messageId).bodySize; - } - - public ContentBody getContentBody(long messageId, int index) throws AMQException, IllegalArgumentException - { - if (index > _contentBodies.size() - 1) - { - throw new IllegalArgumentException("Index " + index + " out of valid range 0 to " + - (_contentBodies.size() - 1)); - } - WeakReference wr = _contentBodies.get(index); - ContentBody cb = wr.get(); - if (cb == null) - { - cb = _messageStore.getContentBodyChunk(messageId, index); - _contentBodies.set(index, new WeakReference(cb)); - } - return cb; - } - - public void addContentBodyFrame(long messageId, ContentBody contentBody) throws AMQException - { - _contentBodies.add(new WeakReference(contentBody)); - _messageStore.storeContentBodyChunk(messageId, _contentBodies.size() - 1, contentBody); - } - - public BasicPublishBody getPublishBody(long messageId) throws AMQException - { - BasicPublishBody bpb = _publishBody.get(); - if (bpb == null) - { - MessageMetaData mmd = _messageStore.getMessageMetaData(messageId); - bpb = mmd.getPublishBody(); - _publishBody = new WeakReference(bpb); - _contentHeaderBody = new WeakReference(mmd.getContentHeaderBody()); - } - return bpb; - } - - public boolean isRedelivered() - { - return _redelivered; - } - - public boolean isPersistent(long messageId) throws AMQException - { - //todo remove literal values to a constant file such as AMQConstants in common - ContentHeaderBody chb = getContentHeaderBody(messageId); - return chb.properties instanceof BasicContentHeaderProperties && - ((BasicContentHeaderProperties) chb.properties).getDeliveryMode() == 2; - } - - /** - * This is called when all the content has been received. - * @param publishBody - * @param contentHeaderBody - * @throws AMQException - */ - public void setPublishAndContentHeaderBody(long messageId, BasicPublishBody publishBody, - ContentHeaderBody contentHeaderBody) - throws AMQException - { - _messageStore.storeMessageMetaData(messageId, new MessageMetaData(publishBody, contentHeaderBody, - _contentBodies.size())); - _publishBody = new WeakReference(publishBody); - _contentHeaderBody = new WeakReference(contentHeaderBody); - } - - public void removeMessage(long messageId) throws AMQException - { - _messageStore.removeMessage(messageId); - } - - public void enqueue(long messageId, AMQQueue queue) throws AMQException - { - _messageStore.enqueueMessage(queue.getName(), messageId); - } - - public void dequeue(long messageId, AMQQueue queue) throws AMQException - { - _messageStore.dequeueMessage(queue.getName(), messageId); - } -} 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 adf6aefdfb..0000000000 --- a/java/broker/src/org/apache/qpid/server/queue/WeightedSubscriptionManager.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -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 50f3d711ab..0000000000 --- a/java/broker/src/org/apache/qpid/server/registry/ApplicationRegistry.java +++ /dev/null @@ -1,197 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -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 db79ae8876..0000000000 --- a/java/broker/src/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java +++ /dev/null @@ -1,155 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -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 0102f78424..0000000000 --- a/java/broker/src/org/apache/qpid/server/registry/IApplicationRegistry.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -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 0adb7b98e2..0000000000 --- a/java/broker/src/org/apache/qpid/server/security/auth/AuthenticationManager.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -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 71e3c81ae4..0000000000 --- a/java/broker/src/org/apache/qpid/server/security/auth/AuthenticationProviderInitialiser.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -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 d7dcf2c973..0000000000 --- a/java/broker/src/org/apache/qpid/server/security/auth/AuthenticationResult.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -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 bfd2ac1b9f..0000000000 --- a/java/broker/src/org/apache/qpid/server/security/auth/CRAMMD5Initialiser.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -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 1477b33ebe..0000000000 --- a/java/broker/src/org/apache/qpid/server/security/auth/JCAProvider.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -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 95a53951ad..0000000000 --- a/java/broker/src/org/apache/qpid/server/security/auth/NullAuthenticationManager.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -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 fb11b89367..0000000000 --- a/java/broker/src/org/apache/qpid/server/security/auth/PasswordFilePrincipalDatabase.java +++ /dev/null @@ -1,130 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -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 8add5455ee..0000000000 --- a/java/broker/src/org/apache/qpid/server/security/auth/PrincipalDatabase.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -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 7d0b60d95e..0000000000 --- a/java/broker/src/org/apache/qpid/server/security/auth/SASLAuthenticationManager.java +++ /dev/null @@ -1,224 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -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 02a953f47c..0000000000 --- a/java/broker/src/org/apache/qpid/server/security/auth/UsernamePasswordInitialiser.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -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 1d425b8399..0000000000 --- a/java/broker/src/org/apache/qpid/server/security/auth/UsernamePrincipal.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -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 94406237a5..0000000000 --- a/java/broker/src/org/apache/qpid/server/security/auth/amqplain/AmqPlainInitialiser.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -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 0f7981abe1..0000000000 --- a/java/broker/src/org/apache/qpid/server/security/auth/amqplain/AmqPlainSaslServer.java +++ /dev/null @@ -1,120 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -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 c4e904f923..0000000000 --- a/java/broker/src/org/apache/qpid/server/security/auth/amqplain/AmqPlainSaslServerFactory.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -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 7b055a4f58..0000000000 --- a/java/broker/src/org/apache/qpid/server/security/auth/plain/PlainInitialiser.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -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 5a69ed02ba..0000000000 --- a/java/broker/src/org/apache/qpid/server/security/auth/plain/PlainSaslServer.java +++ /dev/null @@ -1,141 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -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 754ecbde78..0000000000 --- a/java/broker/src/org/apache/qpid/server/security/auth/plain/PlainSaslServerFactory.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -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 46d46eb4c0..0000000000 --- a/java/broker/src/org/apache/qpid/server/state/AMQState.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -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 54c8bcd9d5..0000000000 --- a/java/broker/src/org/apache/qpid/server/state/AMQStateManager.java +++ /dev/null @@ -1,219 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -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 c77cb4f833..0000000000 --- a/java/broker/src/org/apache/qpid/server/state/IllegalStateTransitionException.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -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 9776151c28..0000000000 --- a/java/broker/src/org/apache/qpid/server/state/StateAwareMethodListener.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -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 d31e786ef1..0000000000 --- a/java/broker/src/org/apache/qpid/server/state/StateListener.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -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 0a243fa138..0000000000 --- a/java/broker/src/org/apache/qpid/server/store/MemoryMessageStore.java +++ /dev/null @@ -1,172 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -package org.apache.qpid.server.store; - -import org.apache.commons.configuration.Configuration; -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.ContentBody; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.queue.MessageMetaData; -import org.apache.qpid.server.queue.QueueRegistry; - -import java.util.ArrayList; -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 _metaDataMap; - - protected ConcurrentMap> _contentBodyMap; - - private final AtomicLong _messageId = new AtomicLong(1); - - public void configure() - { - _log.info("Using capacity " + DEFAULT_HASHTABLE_CAPACITY + " for hash tables"); - _metaDataMap = new ConcurrentHashMap(DEFAULT_HASHTABLE_CAPACITY); - _contentBodyMap = 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 tables"); - _metaDataMap = new ConcurrentHashMap(hashtableCapacity); - _contentBodyMap = new ConcurrentHashMap>(hashtableCapacity); - } - - public void configure(QueueRegistry queueRegistry, String base, Configuration config) throws Exception - { - configure(base, config); - } - - public void close() throws Exception - { - if (_metaDataMap != null) - { - _metaDataMap.clear(); - _metaDataMap = null; - } - if (_contentBodyMap != null) - { - _contentBodyMap.clear(); - _contentBodyMap = null; - } - } - - public void removeMessage(long messageId) - { - if (_log.isDebugEnabled()) - { - _log.debug("Removing message with id " + messageId); - } - _metaDataMap.remove(messageId); - _contentBodyMap.remove(messageId); - } - - public void createQueue(AMQQueue queue) throws AMQException - { - // Not required to do anything - } - - public void removeQueue(String name) throws AMQException - { - // Not required to do anything - } - - public void enqueueMessage(String name, long messageId) throws AMQException - { - // Not required to do anything - } - - public void dequeueMessage(String name, long messageId) throws AMQException - { - // Not required to do anything - } - - public void beginTran() throws AMQException - { - // Not required to do anything - } - - public void commitTran() throws AMQException - { - // Not required to do anything - } - - public void abortTran() throws AMQException - { - // Not required to do anything - } - - public boolean inTran() - { - return false; - } - - public List createQueues() throws AMQException - { - return null; - } - - public long getNewMessageId() - { - return _messageId.getAndIncrement(); - } - - public void storeContentBodyChunk(long messageId, int index, ContentBody contentBody) throws AMQException - { - List bodyList = _contentBodyMap.get(messageId); - if (bodyList == null) - { - bodyList = new ArrayList(); - _contentBodyMap.put(messageId, bodyList); - } - - bodyList.add(index, contentBody); - } - - public void storeMessageMetaData(long messageId, MessageMetaData messageMetaData) throws AMQException - { - _metaDataMap.put(messageId, messageMetaData); - } - - public MessageMetaData getMessageMetaData(long messageId) throws AMQException - { - return _metaDataMap.get(messageId); - } - - public ContentBody getContentBodyChunk(long messageId, int index) throws AMQException - { - List bodyList = _contentBodyMap.get(messageId); - return bodyList.get(index); - } -} 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 c0e8d0465b..0000000000 --- a/java/broker/src/org/apache/qpid/server/store/MessageStore.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -package org.apache.qpid.server.store; - -import org.apache.commons.configuration.Configuration; -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.ContentBody; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.queue.MessageMetaData; -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 - * @throws Exception if an error occurs that means the store is unable to configure itself - */ - void configure(QueueRegistry queueRegistry, String base, Configuration config) throws Exception; - - /** - * Called to close and cleanup any resources used by the message store. - * @throws Exception if close fails - */ - void close() throws Exception; - - 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(); - - void storeContentBodyChunk(long messageId, int index, ContentBody contentBody) throws AMQException; - - void storeMessageMetaData(long messageId, MessageMetaData messageMetaData) throws AMQException; - - MessageMetaData getMessageMetaData(long messageId) throws AMQException; - - ContentBody getContentBodyChunk(long messageId, int index) throws AMQException; - -} 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 6470d876bb..0000000000 --- a/java/broker/src/org/apache/qpid/server/transport/ConnectorConfiguration.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -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 e3d87f808c..0000000000 --- a/java/broker/src/org/apache/qpid/server/transport/ThreadPoolFilter.java +++ /dev/null @@ -1,692 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -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/CleanupMessageOperation.java b/java/broker/src/org/apache/qpid/server/txn/CleanupMessageOperation.java deleted file mode 100644 index 7ff609b750..0000000000 --- a/java/broker/src/org/apache/qpid/server/txn/CleanupMessageOperation.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -package org.apache.qpid.server.txn; - -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; -import org.apache.qpid.server.queue.AMQMessage; -import org.apache.qpid.server.queue.NoConsumersException; -import org.apache.qpid.server.RequiredDeliveryException; - -import java.util.List; - -/** - * @author Apache Software Foundation - */ -public class CleanupMessageOperation implements TxnOp -{ - private static final Logger _log = Logger.getLogger(CleanupMessageOperation.class); - - private final AMQMessage _msg; - - private final List _returns; - - public CleanupMessageOperation(AMQMessage msg, List returns) - { - _msg = msg; - _returns = returns; - } - - 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); - } - catch (AMQException e) - { - _log.error("On commiting transaction, unable to determine whether delivered to a consumer immediately: " + - e, e); - } - } - - public void rollback() - { - } -} diff --git a/java/broker/src/org/apache/qpid/server/txn/DeliverMessageOperation.java b/java/broker/src/org/apache/qpid/server/txn/DeliverMessageOperation.java deleted file mode 100644 index 059c13c687..0000000000 --- a/java/broker/src/org/apache/qpid/server/txn/DeliverMessageOperation.java +++ /dev/null @@ -1,61 +0,0 @@ -/** - * User: Robert Greig - * Date: 01-Nov-2006 - ****************************************************************************** - * (c) Copyright JP Morgan Chase Ltd 2006. All rights reserved. No part of - * this program may be photocopied reproduced or translated to another - * program language without prior written consent of JP Morgan Chase Ltd - ******************************************************************************/ -package org.apache.qpid.server.txn; - -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; -import org.apache.qpid.server.queue.AMQMessage; -import org.apache.qpid.server.queue.AMQQueue; - -/** - * @author Robert Greig (robert.j.greig@jpmorgan.com) - */ -public class DeliverMessageOperation implements TxnOp -{ - private static final Logger _logger = Logger.getLogger(DeliverMessageOperation.class); - - private final AMQMessage _msg; - - private final AMQQueue _queue; - - public DeliverMessageOperation(AMQMessage msg, AMQQueue queue) - { - _msg = msg; - _queue = queue; - _msg.incrementReference(); - } - - public void prepare() throws AMQException - { - } - - public void undoPrepare() - { - } - - public void commit() - { - //do the memeory part of the record() - _msg.incrementReference(); - //then process the message - try - { - _queue.process(_msg); - } - catch (AMQException 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/txn/LocalTransactionalContext.java b/java/broker/src/org/apache/qpid/server/txn/LocalTransactionalContext.java deleted file mode 100644 index df6520e0a8..0000000000 --- a/java/broker/src/org/apache/qpid/server/txn/LocalTransactionalContext.java +++ /dev/null @@ -1,149 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -package org.apache.qpid.server.txn; - -import org.apache.qpid.AMQException; -import org.apache.qpid.server.ack.TxAck; -import org.apache.qpid.server.ack.UnacknowledgedMessageMap; -import org.apache.qpid.server.queue.AMQMessage; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.RequiredDeliveryException; -import org.apache.qpid.server.store.MessageStore; - -import java.util.List; - -/** - * A transactional context that only supports local transactions. - */ -public class LocalTransactionalContext implements TransactionalContext -{ - private final TxnBuffer _txnBuffer; - - /** - * We keep hold of the ack operation so that we can consolidate acks, i.e. multiple acks within a txn are - * consolidated into a single operation - */ - private TxAck _ackOp; - - private List _returnMessages; - - private final MessageStore _messageStore; - - private boolean _inTran = false; - - public LocalTransactionalContext(MessageStore messageStore, - TxnBuffer txnBuffer, List returnMessages) - { - _messageStore = messageStore; - _txnBuffer = txnBuffer; - _returnMessages = returnMessages; - _txnBuffer.enlist(new StoreMessageOperation(messageStore)); - } - - public void rollback() throws AMQException - { - _txnBuffer.rollback(); - } - - public void deliver(AMQMessage message, AMQQueue queue) throws AMQException - { - // don't create a transaction unless needed - if (message.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. - - _txnBuffer.enlist(new DeliverMessageOperation(message, queue)); - _txnBuffer.enlist(new CleanupMessageOperation(message, _returnMessages)); - } - - private void checkAck(long deliveryTag, UnacknowledgedMessageMap unacknowledgedMessageMap) throws AMQException - { - if (!unacknowledgedMessageMap.contains(deliveryTag)) - { - throw new AMQException("Ack with delivery tag " + deliveryTag + " not known for channel"); - } - } - - public void acknowledgeMessage(long deliveryTag, long lastDeliveryTag, boolean multiple, - UnacknowledgedMessageMap unacknowledgedMessageMap) throws AMQException - { - //check that the tag exists to give early failure - if (!multiple || deliveryTag > 0) - { - checkAck(deliveryTag, unacknowledgedMessageMap); - } - //we use a single txn op for all acks and update this op - //as new acks come in. If this is the first ack in the txn - //we will need to create and enlist the op. - if (_ackOp == null) - { - _ackOp = new TxAck(unacknowledgedMessageMap); - _txnBuffer.enlist(_ackOp); - } - // update the op to include this ack request - if (multiple && deliveryTag == 0) - { - // if have signalled to ack all, that refers only - // to all at this time - _ackOp.update(lastDeliveryTag, multiple); - } - else - { - _ackOp.update(deliveryTag, multiple); - } - } - - public void messageFullyReceived(boolean persistent) throws AMQException - { - // Not required in this transactional context - } - - public void beginTranIfNecessary() throws AMQException - { - if (!_inTran) - { - _messageStore.beginTran(); - _inTran = true; - } - } - - public void commit() throws AMQException - { - if (_ackOp != null) - { - _ackOp.consolidate(); - if (_ackOp.checkPersistent()) - { - _txnBuffer.containsPersistentChanges(); - } - //already enlisted, after commit will reset regardless of outcome - _ackOp = null; - } - - _txnBuffer.commit(); - //TODO: may need to return 'immediate' messages at this point - } -} diff --git a/java/broker/src/org/apache/qpid/server/txn/NonTransactionalContext.java b/java/broker/src/org/apache/qpid/server/txn/NonTransactionalContext.java deleted file mode 100644 index 9c8e7c7002..0000000000 --- a/java/broker/src/org/apache/qpid/server/txn/NonTransactionalContext.java +++ /dev/null @@ -1,171 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -package org.apache.qpid.server.txn; - -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; -import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.server.RequiredDeliveryException; -import org.apache.qpid.server.ack.UnacknowledgedMessage; -import org.apache.qpid.server.ack.UnacknowledgedMessageMap; -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 java.util.LinkedList; -import java.util.List; - -/** - * @author Apache Software Foundation - */ -public class NonTransactionalContext implements TransactionalContext -{ - private static final Logger _log = Logger.getLogger(NonTransactionalContext.class); - - /** - * Channel is useful for logging - */ - private final AMQChannel _channel; - - /** - * Where to put undeliverable messages - */ - private final List _returnMessages; - - private final MessageStore _messageStore; - - /** - * Whether we are in a transaction - */ - private boolean _inTran; - - public NonTransactionalContext(MessageStore messageStore, AMQChannel channel, - List returnMessages) - { - _channel = channel; - _returnMessages = returnMessages; - _messageStore = messageStore; - } - - public void beginTranIfNecessary() throws AMQException - { - if (!_inTran) - { - _messageStore.beginTran(); - _inTran = true; - } - } - - public void commit() throws AMQException - { - // Does not apply to this context - } - - public void rollback() throws AMQException - { - // Does not apply to this context - } - - public void deliver(AMQMessage message, AMQQueue queue) throws AMQException - { - try - { - message.incrementReference(); - queue.process(message); - //following check implements the functionality - //required by the 'immediate' flag: - message.checkDeliveredToConsumer(); - } - catch (NoConsumersException e) - { - _returnMessages.add(e); - } - } - - public void acknowledgeMessage(final long deliveryTag, long lastDeliveryTag, - boolean multiple, final UnacknowledgedMessageMap unacknowledgedMessageMap) - throws AMQException - { - if (multiple) - { - if (deliveryTag == 0) - { - - //Spec 2.1.6.11 ... If the multiple field is 1, and the delivery tag is zero, - // tells the server to acknowledge all outstanding mesages. - _log.info("Multiple ack on delivery tag 0. ACKing all messages. Current count:" + - unacknowledgedMessageMap.size()); - unacknowledgedMessageMap.visit(new UnacknowledgedMessageMap.Visitor() - { - public boolean callback(UnacknowledgedMessage message) throws AMQException - { - message.discard(); - return false; - } - - public void visitComplete() - { - unacknowledgedMessageMap.clear(); - } - }); - } - else - { - if (!unacknowledgedMessageMap.contains(deliveryTag)) - { - throw new AMQException("Multiple ack on delivery tag " + deliveryTag + " not known for channel"); - } - - LinkedList acked = new LinkedList(); - unacknowledgedMessageMap.drainTo(acked, deliveryTag); - for (UnacknowledgedMessage msg : acked) - { - msg.discard(); - } - } - } - else - { - UnacknowledgedMessage msg; - msg = unacknowledgedMessageMap.remove(deliveryTag); - - if (msg == null) - { - _log.info("Single ack on delivery tag " + deliveryTag + " not known for channel:" + - _channel.getChannelId()); - throw new AMQException("Single ack on delivery tag " + deliveryTag + " not known for channel:" + - _channel.getChannelId()); - } - msg.discard(); - if (_log.isDebugEnabled()) - { - _log.debug("Received non-multiple ack for messaging with delivery tag " + deliveryTag); - } - } - } - - public void messageFullyReceived(boolean persistent) throws AMQException - { - if (persistent) - { - _messageStore.commitTran(); - _inTran = false; - } - } -} diff --git a/java/broker/src/org/apache/qpid/server/txn/StoreMessageOperation.java b/java/broker/src/org/apache/qpid/server/txn/StoreMessageOperation.java deleted file mode 100644 index 2a3b524060..0000000000 --- a/java/broker/src/org/apache/qpid/server/txn/StoreMessageOperation.java +++ /dev/null @@ -1,45 +0,0 @@ -/** - * User: Robert Greig - * Date: 01-Nov-2006 - ****************************************************************************** - * (c) Copyright JP Morgan Chase Ltd 2006. All rights reserved. No part of - * this program may be photocopied reproduced or translated to another - * program language without prior written consent of JP Morgan Chase Ltd - ******************************************************************************/ -package org.apache.qpid.server.txn; - -import org.apache.qpid.AMQException; -import org.apache.qpid.server.store.MessageStore; - -/** - * A transactional operation to store messages in an underlying persistent store. When this operation - * commits it will do everything to ensure that all messages are safely committed to persistent - * storage. - */ -public class StoreMessageOperation implements TxnOp -{ - private final MessageStore _messsageStore; - - public StoreMessageOperation(MessageStore messageStore) - { - _messsageStore = messageStore; - } - - public void prepare() throws AMQException - { - } - - public void undoPrepare() - { - } - - public void commit() throws AMQException - { - _messsageStore.commitTran(); - } - - public void rollback() throws AMQException - { - _messsageStore.abortTran(); - } -} diff --git a/java/broker/src/org/apache/qpid/server/txn/TransactionalContext.java b/java/broker/src/org/apache/qpid/server/txn/TransactionalContext.java deleted file mode 100644 index 1ec216cc8b..0000000000 --- a/java/broker/src/org/apache/qpid/server/txn/TransactionalContext.java +++ /dev/null @@ -1,33 +0,0 @@ -/** - * User: Robert Greig - * Date: 01-Nov-2006 - ****************************************************************************** - * (c) Copyright JP Morgan Chase Ltd 2006. All rights reserved. No part of - * this program may be photocopied reproduced or translated to another - * program language without prior written consent of JP Morgan Chase Ltd - ******************************************************************************/ -package org.apache.qpid.server.txn; - -import org.apache.qpid.AMQException; -import org.apache.qpid.server.ack.UnacknowledgedMessageMap; -import org.apache.qpid.server.queue.AMQMessage; -import org.apache.qpid.server.queue.AMQQueue; - -/** - * @author Robert Greig (robert.j.greig@jpmorgan.com) - */ -public interface TransactionalContext -{ - void beginTranIfNecessary() throws AMQException; - - void commit() throws AMQException; - - void rollback() throws AMQException; - - void deliver(AMQMessage message, AMQQueue queue) throws AMQException; - - void acknowledgeMessage(long deliveryTag, long lastDeliveryTag, boolean multiple, - UnacknowledgedMessageMap unacknowledgedMessageMap) throws AMQException; - - void messageFullyReceived(boolean persistent) throws AMQException; -} 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 4e141495c2..0000000000 --- a/java/broker/src/org/apache/qpid/server/txn/TxnBuffer.java +++ /dev/null @@ -1,119 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -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."); - if (prepare()) - { - _log.debug("Transaction Succeeded"); - for (TxnOp op : _ops) - { - op.commit(); - } - } - else - { - _log.debug("Transaction Failed"); - } - } - 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 1a81786460..0000000000 --- a/java/broker/src/org/apache/qpid/server/txn/TxnOp.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -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() throws AMQException; - /** - * This is not the same as rollback. Unfortunately the use of an - * in memory reference count as a locking mechanism and a test for - * whether a message should be deleted means that as things are, - * handling an acknowledgement unavoidably alters both memory and - * persistent state on prepare. This is needed to 'compensate' or - * undo the in-memory change if the peristent update of later ops - * fails. - */ - public void undoPrepare(); - /** - * Rolls back the operation. - */ - public void rollback() throws AMQException; -} 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 d2c10cb4d1..0000000000 --- a/java/broker/src/org/apache/qpid/server/util/CircularBuffer.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -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/LoggingProxy.java b/java/broker/src/org/apache/qpid/server/util/LoggingProxy.java deleted file mode 100644 index 03c4896422..0000000000 --- a/java/broker/src/org/apache/qpid/server/util/LoggingProxy.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -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 0fab1f6895..0000000000 --- a/java/broker/src/org/apache/qpid/server/util/NullApplicationRegistry.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -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; - } -} - -- cgit v1.2.1